]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 5.4
authorSasha Levin <sashal@kernel.org>
Wed, 2 Oct 2024 05:17:36 +0000 (01:17 -0400)
committerSasha Levin <sashal@kernel.org>
Wed, 2 Oct 2024 05:17:36 +0000 (01:17 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-5.4/asoc-meson-axg-card-fix-use-after-free.patch [new file with mode: 0644]
queue-5.4/asoc-meson-axg-extract-sound-card-utils.patch [new file with mode: 0644]
queue-5.4/pci-xilinx-nwl-fix-off-by-one-in-intx-irq-handler.patch [new file with mode: 0644]
queue-5.4/pci-xilinx-nwl-use-irq_data_get_irq_chip_data.patch [new file with mode: 0644]
queue-5.4/pps-add-an-error-check-in-parport_attach.patch [new file with mode: 0644]
queue-5.4/pps-remove-usage-of-the-deprecated-ida_simple_xx-api.patch [new file with mode: 0644]
queue-5.4/series
queue-5.4/soc-versatile-realview-fix-memory-leak-during-device.patch [new file with mode: 0644]
queue-5.4/soc-versatile-realview-fix-soc_dev-leak-during-devic.patch [new file with mode: 0644]
queue-5.4/usb-misc-yurex-fix-race-between-read-and-write.patch [new file with mode: 0644]
queue-5.4/usb-yurex-replace-snprintf-with-the-safer-scnprintf-.patch [new file with mode: 0644]

diff --git a/queue-5.4/asoc-meson-axg-card-fix-use-after-free.patch b/queue-5.4/asoc-meson-axg-card-fix-use-after-free.patch
new file mode 100644 (file)
index 0000000..4f8cec4
--- /dev/null
@@ -0,0 +1,87 @@
+From b86366b5b927e9ff0fd2bfe02b65aaa3accabbf3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Sep 2024 17:24:25 +0300
+Subject: ASoC: meson: axg-card: fix 'use-after-free'
+
+From: Arseniy Krasnov <avkrasnov@salutedevices.com>
+
+[ Upstream commit 4f9a71435953f941969a4f017e2357db62d85a86 ]
+
+Buffer 'card->dai_link' is reallocated in 'meson_card_reallocate_links()',
+so move 'pad' pointer initialization after this function when memory is
+already reallocated.
+
+Kasan bug report:
+
+==================================================================
+BUG: KASAN: slab-use-after-free in axg_card_add_link+0x76c/0x9bc
+Read of size 8 at addr ffff000000e8b260 by task modprobe/356
+
+CPU: 0 PID: 356 Comm: modprobe Tainted: G O 6.9.12-sdkernel #1
+Call trace:
+ dump_backtrace+0x94/0xec
+ show_stack+0x18/0x24
+ dump_stack_lvl+0x78/0x90
+ print_report+0xfc/0x5c0
+ kasan_report+0xb8/0xfc
+ __asan_load8+0x9c/0xb8
+ axg_card_add_link+0x76c/0x9bc [snd_soc_meson_axg_sound_card]
+ meson_card_probe+0x344/0x3b8 [snd_soc_meson_card_utils]
+ platform_probe+0x8c/0xf4
+ really_probe+0x110/0x39c
+ __driver_probe_device+0xb8/0x18c
+ driver_probe_device+0x108/0x1d8
+ __driver_attach+0xd0/0x25c
+ bus_for_each_dev+0xe0/0x154
+ driver_attach+0x34/0x44
+ bus_add_driver+0x134/0x294
+ driver_register+0xa8/0x1e8
+ __platform_driver_register+0x44/0x54
+ axg_card_pdrv_init+0x20/0x1000 [snd_soc_meson_axg_sound_card]
+ do_one_initcall+0xdc/0x25c
+ do_init_module+0x10c/0x334
+ load_module+0x24c4/0x26cc
+ init_module_from_file+0xd4/0x128
+ __arm64_sys_finit_module+0x1f4/0x41c
+ invoke_syscall+0x60/0x188
+ el0_svc_common.constprop.0+0x78/0x13c
+ do_el0_svc+0x30/0x40
+ el0_svc+0x38/0x78
+ el0t_64_sync_handler+0x100/0x12c
+ el0t_64_sync+0x190/0x194
+
+Fixes: 7864a79f37b5 ("ASoC: meson: add axg sound card support")
+Cc: Stable@vger.kernel.org
+Signed-off-by: Arseniy Krasnov <avkrasnov@salutedevices.com>
+Reviewed-by: Jerome Brunet <jbrunet@baylibre.com>
+Link: https://patch.msgid.link/20240911142425.598631-1-avkrasnov@salutedevices.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/meson/axg-card.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c
+index 6bb3a8f0a788d..a369c18531876 100644
+--- a/sound/soc/meson/axg-card.c
++++ b/sound/soc/meson/axg-card.c
+@@ -104,7 +104,7 @@ static int axg_card_add_tdm_loopback(struct snd_soc_card *card,
+                                    int *index)
+ {
+       struct meson_card *priv = snd_soc_card_get_drvdata(card);
+-      struct snd_soc_dai_link *pad = &card->dai_link[*index];
++      struct snd_soc_dai_link *pad;
+       struct snd_soc_dai_link *lb;
+       struct snd_soc_dai_link_component *dlc;
+       int ret;
+@@ -114,6 +114,7 @@ static int axg_card_add_tdm_loopback(struct snd_soc_card *card,
+       if (ret)
+               return ret;
++      pad = &card->dai_link[*index];
+       lb = &card->dai_link[*index + 1];
+       lb->name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-lb", pad->name);
+-- 
+2.43.0
+
diff --git a/queue-5.4/asoc-meson-axg-extract-sound-card-utils.patch b/queue-5.4/asoc-meson-axg-extract-sound-card-utils.patch
new file mode 100644 (file)
index 0000000..ab9bebc
--- /dev/null
@@ -0,0 +1,1048 @@
+From b5acf3f40a49beb3d71fe3e1c074ff6105f3fbcc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 13 Feb 2020 16:51:57 +0100
+Subject: ASoC: meson: axg: extract sound card utils
+
+From: Jerome Brunet <jbrunet@baylibre.com>
+
+[ Upstream commit aa9c3b7273a58b5d9b2c1161b76b5fc8ea8c159b ]
+
+This prepares the addition of the GX SoC family sound card driver.
+The GX sound card, while slightly different, will be similar to the
+AXG one. The purpose of this change is to share the utils common to
+both sound card driver.
+
+Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
+Link: https://lore.kernel.org/r/20200213155159.3235792-8-jbrunet@baylibre.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: 4f9a71435953 ("ASoC: meson: axg-card: fix 'use-after-free'")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/meson/Kconfig            |   4 +
+ sound/soc/meson/Makefile           |   2 +
+ sound/soc/meson/axg-card.c         | 403 ++---------------------------
+ sound/soc/meson/meson-card-utils.c | 385 +++++++++++++++++++++++++++
+ sound/soc/meson/meson-card.h       |  55 ++++
+ 5 files changed, 473 insertions(+), 376 deletions(-)
+ create mode 100644 sound/soc/meson/meson-card-utils.c
+ create mode 100644 sound/soc/meson/meson-card.h
+
+diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
+index f9188274f6b0f..ce15de42945b5 100644
+--- a/sound/soc/meson/Kconfig
++++ b/sound/soc/meson/Kconfig
+@@ -50,6 +50,7 @@ config SND_MESON_AXG_TDMOUT
+ config SND_MESON_AXG_SOUND_CARD
+       tristate "Amlogic AXG Sound Card Support"
+       select SND_MESON_AXG_TDM_INTERFACE
++      select SND_MESON_CARD_UTILS
+       imply SND_MESON_AXG_FRDDR
+       imply SND_MESON_AXG_TODDR
+       imply SND_MESON_AXG_TDMIN
+@@ -85,6 +86,9 @@ config SND_MESON_AXG_PDM
+         Select Y or M to add support for PDM input embedded
+         in the Amlogic AXG SoC family
++config SND_MESON_CARD_UTILS
++       tristate
++
+ config SND_MESON_CODEC_GLUE
+       tristate
+diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
+index 529a807b3f376..6e248260617fe 100644
+--- a/sound/soc/meson/Makefile
++++ b/sound/soc/meson/Makefile
+@@ -11,6 +11,7 @@ snd-soc-meson-axg-sound-card-objs := axg-card.o
+ snd-soc-meson-axg-spdifin-objs := axg-spdifin.o
+ snd-soc-meson-axg-spdifout-objs := axg-spdifout.o
+ snd-soc-meson-axg-pdm-objs := axg-pdm.o
++snd-soc-meson-card-utils-objs := meson-card-utils.o
+ snd-soc-meson-codec-glue-objs := meson-codec-glue.o
+ snd-soc-meson-g12a-tohdmitx-objs := g12a-tohdmitx.o
+@@ -25,5 +26,6 @@ obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o
+ obj-$(CONFIG_SND_MESON_AXG_SPDIFIN) += snd-soc-meson-axg-spdifin.o
+ obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o
+ obj-$(CONFIG_SND_MESON_AXG_PDM) += snd-soc-meson-axg-pdm.o
++obj-$(CONFIG_SND_MESON_CARD_UTILS) += snd-soc-meson-card-utils.o
+ obj-$(CONFIG_SND_MESON_CODEC_GLUE) += snd-soc-meson-codec-glue.o
+ obj-$(CONFIG_SND_MESON_G12A_TOHDMITX) += snd-soc-meson-g12a-tohdmitx.o
+diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c
+index 7126344017fa6..6bb3a8f0a788d 100644
+--- a/sound/soc/meson/axg-card.c
++++ b/sound/soc/meson/axg-card.c
+@@ -9,11 +9,7 @@
+ #include <sound/soc-dai.h>
+ #include "axg-tdm.h"
+-
+-struct axg_card {
+-      struct snd_soc_card card;
+-      void **link_data;
+-};
++#include "meson-card.h"
+ struct axg_dai_link_tdm_mask {
+       u32 tx;
+@@ -41,161 +37,15 @@ static const struct snd_soc_pcm_stream codec_params = {
+       .channels_max = 8,
+ };
+-#define PREFIX "amlogic,"
+-
+-static int axg_card_reallocate_links(struct axg_card *priv,
+-                                   unsigned int num_links)
+-{
+-      struct snd_soc_dai_link *links;
+-      void **ldata;
+-
+-      links = krealloc(priv->card.dai_link,
+-                       num_links * sizeof(*priv->card.dai_link),
+-                       GFP_KERNEL | __GFP_ZERO);
+-      ldata = krealloc(priv->link_data,
+-                       num_links * sizeof(*priv->link_data),
+-                       GFP_KERNEL | __GFP_ZERO);
+-
+-      if (!links || !ldata) {
+-              dev_err(priv->card.dev, "failed to allocate links\n");
+-              return -ENOMEM;
+-      }
+-
+-      priv->card.dai_link = links;
+-      priv->link_data = ldata;
+-      priv->card.num_links = num_links;
+-      return 0;
+-}
+-
+-static int axg_card_parse_dai(struct snd_soc_card *card,
+-                            struct device_node *node,
+-                            struct device_node **dai_of_node,
+-                            const char **dai_name)
+-{
+-      struct of_phandle_args args;
+-      int ret;
+-
+-      if (!dai_name || !dai_of_node || !node)
+-              return -EINVAL;
+-
+-      ret = of_parse_phandle_with_args(node, "sound-dai",
+-                                       "#sound-dai-cells", 0, &args);
+-      if (ret) {
+-              if (ret != -EPROBE_DEFER)
+-                      dev_err(card->dev, "can't parse dai %d\n", ret);
+-              return ret;
+-      }
+-      *dai_of_node = args.np;
+-
+-      return snd_soc_get_dai_name(&args, dai_name);
+-}
+-
+-static int axg_card_set_link_name(struct snd_soc_card *card,
+-                                struct snd_soc_dai_link *link,
+-                                struct device_node *node,
+-                                const char *prefix)
+-{
+-      char *name = devm_kasprintf(card->dev, GFP_KERNEL, "%s.%s",
+-                                  prefix, node->full_name);
+-      if (!name)
+-              return -ENOMEM;
+-
+-      link->name = name;
+-      link->stream_name = name;
+-
+-      return 0;
+-}
+-
+-static void axg_card_clean_references(struct axg_card *priv)
+-{
+-      struct snd_soc_card *card = &priv->card;
+-      struct snd_soc_dai_link *link;
+-      struct snd_soc_dai_link_component *codec;
+-      struct snd_soc_aux_dev *aux;
+-      int i, j;
+-
+-      if (card->dai_link) {
+-              for_each_card_prelinks(card, i, link) {
+-                      if (link->cpus)
+-                              of_node_put(link->cpus->of_node);
+-                      for_each_link_codecs(link, j, codec)
+-                              of_node_put(codec->of_node);
+-              }
+-      }
+-
+-      if (card->aux_dev) {
+-              for_each_card_pre_auxs(card, i, aux)
+-                      of_node_put(aux->dlc.of_node);
+-      }
+-
+-      kfree(card->dai_link);
+-      kfree(priv->link_data);
+-}
+-
+-static int axg_card_add_aux_devices(struct snd_soc_card *card)
+-{
+-      struct device_node *node = card->dev->of_node;
+-      struct snd_soc_aux_dev *aux;
+-      int num, i;
+-
+-      num = of_count_phandle_with_args(node, "audio-aux-devs", NULL);
+-      if (num == -ENOENT) {
+-              /*
+-               * It is ok to have no auxiliary devices but for this card it
+-               * is a strange situtation. Let's warn the about it.
+-               */
+-              dev_warn(card->dev, "card has no auxiliary devices\n");
+-              return 0;
+-      } else if (num < 0) {
+-              dev_err(card->dev, "error getting auxiliary devices: %d\n",
+-                      num);
+-              return num;
+-      }
+-
+-      aux = devm_kcalloc(card->dev, num, sizeof(*aux), GFP_KERNEL);
+-      if (!aux)
+-              return -ENOMEM;
+-      card->aux_dev = aux;
+-      card->num_aux_devs = num;
+-
+-      for_each_card_pre_auxs(card, i, aux) {
+-              aux->dlc.of_node =
+-                      of_parse_phandle(node, "audio-aux-devs", i);
+-              if (!aux->dlc.of_node)
+-                      return -EINVAL;
+-      }
+-
+-      return 0;
+-}
+-
+ static int axg_card_tdm_be_hw_params(struct snd_pcm_substream *substream,
+                                    struct snd_pcm_hw_params *params)
+ {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+-      struct axg_card *priv = snd_soc_card_get_drvdata(rtd->card);
++      struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct axg_dai_link_tdm_data *be =
+               (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num];
+-      struct snd_soc_dai *codec_dai;
+-      unsigned int mclk;
+-      int ret, i;
+-
+-      if (be->mclk_fs) {
+-              mclk = params_rate(params) * be->mclk_fs;
+-
+-              for_each_rtd_codec_dai(rtd, i, codec_dai) {
+-                      ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+-                                                   SND_SOC_CLOCK_IN);
+-                      if (ret && ret != -ENOTSUPP)
+-                              return ret;
+-              }
+-
+-              ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk,
+-                                           SND_SOC_CLOCK_OUT);
+-              if (ret && ret != -ENOTSUPP)
+-                      return ret;
+-      }
+-      return 0;
++      return meson_card_i2s_set_sysclk(substream, params, be->mclk_fs);
+ }
+ static const struct snd_soc_ops axg_card_tdm_be_ops = {
+@@ -204,7 +54,7 @@ static const struct snd_soc_ops axg_card_tdm_be_ops = {
+ static int axg_card_tdm_dai_init(struct snd_soc_pcm_runtime *rtd)
+ {
+-      struct axg_card *priv = snd_soc_card_get_drvdata(rtd->card);
++      struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct axg_dai_link_tdm_data *be =
+               (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num];
+       struct snd_soc_dai *codec_dai;
+@@ -234,7 +84,7 @@ static int axg_card_tdm_dai_init(struct snd_soc_pcm_runtime *rtd)
+ static int axg_card_tdm_dai_lb_init(struct snd_soc_pcm_runtime *rtd)
+ {
+-      struct axg_card *priv = snd_soc_card_get_drvdata(rtd->card);
++      struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct axg_dai_link_tdm_data *be =
+               (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num];
+       int ret;
+@@ -253,14 +103,14 @@ static int axg_card_tdm_dai_lb_init(struct snd_soc_pcm_runtime *rtd)
+ static int axg_card_add_tdm_loopback(struct snd_soc_card *card,
+                                    int *index)
+ {
+-      struct axg_card *priv = snd_soc_card_get_drvdata(card);
++      struct meson_card *priv = snd_soc_card_get_drvdata(card);
+       struct snd_soc_dai_link *pad = &card->dai_link[*index];
+       struct snd_soc_dai_link *lb;
+       struct snd_soc_dai_link_component *dlc;
+       int ret;
+       /* extend links */
+-      ret = axg_card_reallocate_links(priv, card->num_links + 1);
++      ret = meson_card_reallocate_links(card, card->num_links + 1);
+       if (ret)
+               return ret;
+@@ -304,32 +154,6 @@ static int axg_card_add_tdm_loopback(struct snd_soc_card *card,
+       return 0;
+ }
+-static unsigned int axg_card_parse_daifmt(struct device_node *node,
+-                                        struct device_node *cpu_node)
+-{
+-      struct device_node *bitclkmaster = NULL;
+-      struct device_node *framemaster = NULL;
+-      unsigned int daifmt;
+-
+-      daifmt = snd_soc_of_parse_daifmt(node, PREFIX,
+-                                       &bitclkmaster, &framemaster);
+-      daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
+-
+-      /* If no master is provided, default to cpu master */
+-      if (!bitclkmaster || bitclkmaster == cpu_node) {
+-              daifmt |= (!framemaster || framemaster == cpu_node) ?
+-                      SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBS_CFM;
+-      } else {
+-              daifmt |= (!framemaster || framemaster == cpu_node) ?
+-                      SND_SOC_DAIFMT_CBM_CFS : SND_SOC_DAIFMT_CBM_CFM;
+-      }
+-
+-      of_node_put(bitclkmaster);
+-      of_node_put(framemaster);
+-
+-      return daifmt;
+-}
+-
+ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card,
+                                       struct snd_soc_dai_link *link,
+                                       struct device_node *node,
+@@ -424,7 +248,7 @@ static int axg_card_parse_tdm(struct snd_soc_card *card,
+                             struct device_node *node,
+                             int *index)
+ {
+-      struct axg_card *priv = snd_soc_card_get_drvdata(card);
++      struct meson_card *priv = snd_soc_card_get_drvdata(card);
+       struct snd_soc_dai_link *link = &card->dai_link[*index];
+       struct axg_dai_link_tdm_data *be;
+       int ret;
+@@ -438,7 +262,7 @@ static int axg_card_parse_tdm(struct snd_soc_card *card,
+       /* Setup tdm link */
+       link->ops = &axg_card_tdm_be_ops;
+       link->init = axg_card_tdm_dai_init;
+-      link->dai_fmt = axg_card_parse_daifmt(node, link->cpus->of_node);
++      link->dai_fmt = meson_card_parse_daifmt(node, link->cpus->of_node);
+       of_property_read_u32(node, "mclk-fs", &be->mclk_fs);
+@@ -462,97 +286,24 @@ static int axg_card_parse_tdm(struct snd_soc_card *card,
+       return 0;
+ }
+-static int axg_card_set_be_link(struct snd_soc_card *card,
+-                              struct snd_soc_dai_link *link,
+-                              struct device_node *node)
+-{
+-      struct snd_soc_dai_link_component *codec;
+-      struct device_node *np;
+-      int ret, num_codecs;
+-
+-      link->no_pcm = 1;
+-      link->dpcm_playback = 1;
+-      link->dpcm_capture = 1;
+-
+-      num_codecs = of_get_child_count(node);
+-      if (!num_codecs) {
+-              dev_err(card->dev, "be link %s has no codec\n",
+-                      node->full_name);
+-              return -EINVAL;
+-      }
+-
+-      codec = devm_kcalloc(card->dev, num_codecs, sizeof(*codec), GFP_KERNEL);
+-      if (!codec)
+-              return -ENOMEM;
+-
+-      link->codecs = codec;
+-      link->num_codecs = num_codecs;
+-
+-      for_each_child_of_node(node, np) {
+-              ret = axg_card_parse_dai(card, np, &codec->of_node,
+-                                       &codec->dai_name);
+-              if (ret) {
+-                      of_node_put(np);
+-                      return ret;
+-              }
+-
+-              codec++;
+-      }
+-
+-      ret = axg_card_set_link_name(card, link, node, "be");
+-      if (ret)
+-              dev_err(card->dev, "error setting %pOFn link name\n", np);
+-
+-      return ret;
+-}
+-
+-static int axg_card_set_fe_link(struct snd_soc_card *card,
+-                              struct snd_soc_dai_link *link,
+-                              struct device_node *node,
+-                              bool is_playback)
+-{
+-      struct snd_soc_dai_link_component *codec;
+-
+-      codec = devm_kzalloc(card->dev, sizeof(*codec), GFP_KERNEL);
+-      if (!codec)
+-              return -ENOMEM;
+-
+-      link->codecs = codec;
+-      link->num_codecs = 1;
+-
+-      link->dynamic = 1;
+-      link->dpcm_merged_format = 1;
+-      link->dpcm_merged_chan = 1;
+-      link->dpcm_merged_rate = 1;
+-      link->codecs->dai_name = "snd-soc-dummy-dai";
+-      link->codecs->name = "snd-soc-dummy";
+-
+-      if (is_playback)
+-              link->dpcm_playback = 1;
+-      else
+-              link->dpcm_capture = 1;
+-
+-      return axg_card_set_link_name(card, link, node, "fe");
+-}
+-
+ static int axg_card_cpu_is_capture_fe(struct device_node *np)
+ {
+-      return of_device_is_compatible(np, PREFIX "axg-toddr");
++      return of_device_is_compatible(np, DT_PREFIX "axg-toddr");
+ }
+ static int axg_card_cpu_is_playback_fe(struct device_node *np)
+ {
+-      return of_device_is_compatible(np, PREFIX "axg-frddr");
++      return of_device_is_compatible(np, DT_PREFIX "axg-frddr");
+ }
+ static int axg_card_cpu_is_tdm_iface(struct device_node *np)
+ {
+-      return of_device_is_compatible(np, PREFIX "axg-tdm-iface");
++      return of_device_is_compatible(np, DT_PREFIX "axg-tdm-iface");
+ }
+ static int axg_card_cpu_is_codec(struct device_node *np)
+ {
+-      return of_device_is_compatible(np, PREFIX "g12a-tohdmitx");
++      return of_device_is_compatible(np, DT_PREFIX "g12a-tohdmitx");
+ }
+ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np,
+@@ -569,17 +320,17 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np,
+       dai_link->cpus = cpu;
+       dai_link->num_cpus = 1;
+-      ret = axg_card_parse_dai(card, np, &dai_link->cpus->of_node,
+-                               &dai_link->cpus->dai_name);
++      ret = meson_card_parse_dai(card, np, &dai_link->cpus->of_node,
++                                 &dai_link->cpus->dai_name);
+       if (ret)
+               return ret;
+       if (axg_card_cpu_is_playback_fe(dai_link->cpus->of_node))
+-              ret = axg_card_set_fe_link(card, dai_link, np, true);
++              ret = meson_card_set_fe_link(card, dai_link, np, true);
+       else if (axg_card_cpu_is_capture_fe(dai_link->cpus->of_node))
+-              ret = axg_card_set_fe_link(card, dai_link, np, false);
++              ret = meson_card_set_fe_link(card, dai_link, np, false);
+       else
+-              ret = axg_card_set_be_link(card, dai_link, np);
++              ret = meson_card_set_be_link(card, dai_link, np);
+       if (ret)
+               return ret;
+@@ -592,121 +343,21 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np,
+       return ret;
+ }
+-static int axg_card_add_links(struct snd_soc_card *card)
+-{
+-      struct axg_card *priv = snd_soc_card_get_drvdata(card);
+-      struct device_node *node = card->dev->of_node;
+-      struct device_node *np;
+-      int num, i, ret;
+-
+-      num = of_get_child_count(node);
+-      if (!num) {
+-              dev_err(card->dev, "card has no links\n");
+-              return -EINVAL;
+-      }
+-
+-      ret = axg_card_reallocate_links(priv, num);
+-      if (ret)
+-              return ret;
+-
+-      i = 0;
+-      for_each_child_of_node(node, np) {
+-              ret = axg_card_add_link(card, np, &i);
+-              if (ret) {
+-                      of_node_put(np);
+-                      return ret;
+-              }
+-
+-              i++;
+-      }
+-
+-      return 0;
+-}
+-
+-static int axg_card_parse_of_optional(struct snd_soc_card *card,
+-                                    const char *propname,
+-                                    int (*func)(struct snd_soc_card *c,
+-                                                const char *p))
+-{
+-      /* If property is not provided, don't fail ... */
+-      if (!of_property_read_bool(card->dev->of_node, propname))
+-              return 0;
+-
+-      /* ... but do fail if it is provided and the parsing fails */
+-      return func(card, propname);
+-}
++static const struct meson_card_match_data axg_card_match_data = {
++      .add_link = axg_card_add_link,
++};
+ static const struct of_device_id axg_card_of_match[] = {
+-      { .compatible = "amlogic,axg-sound-card", },
+-      {}
++      {
++              .compatible = "amlogic,axg-sound-card",
++              .data = &axg_card_match_data,
++      }, {}
+ };
+ MODULE_DEVICE_TABLE(of, axg_card_of_match);
+-static int axg_card_probe(struct platform_device *pdev)
+-{
+-      struct device *dev = &pdev->dev;
+-      struct axg_card *priv;
+-      int ret;
+-
+-      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+-      if (!priv)
+-              return -ENOMEM;
+-
+-      platform_set_drvdata(pdev, priv);
+-      snd_soc_card_set_drvdata(&priv->card, priv);
+-
+-      priv->card.owner = THIS_MODULE;
+-      priv->card.dev = dev;
+-
+-      ret = snd_soc_of_parse_card_name(&priv->card, "model");
+-      if (ret < 0)
+-              return ret;
+-
+-      ret = axg_card_parse_of_optional(&priv->card, "audio-routing",
+-                                       snd_soc_of_parse_audio_routing);
+-      if (ret) {
+-              dev_err(dev, "error while parsing routing\n");
+-              return ret;
+-      }
+-
+-      ret = axg_card_parse_of_optional(&priv->card, "audio-widgets",
+-                                       snd_soc_of_parse_audio_simple_widgets);
+-      if (ret) {
+-              dev_err(dev, "error while parsing widgets\n");
+-              return ret;
+-      }
+-
+-      ret = axg_card_add_links(&priv->card);
+-      if (ret)
+-              goto out_err;
+-
+-      ret = axg_card_add_aux_devices(&priv->card);
+-      if (ret)
+-              goto out_err;
+-
+-      ret = devm_snd_soc_register_card(dev, &priv->card);
+-      if (ret)
+-              goto out_err;
+-
+-      return 0;
+-
+-out_err:
+-      axg_card_clean_references(priv);
+-      return ret;
+-}
+-
+-static int axg_card_remove(struct platform_device *pdev)
+-{
+-      struct axg_card *priv = platform_get_drvdata(pdev);
+-
+-      axg_card_clean_references(priv);
+-
+-      return 0;
+-}
+-
+ static struct platform_driver axg_card_pdrv = {
+-      .probe = axg_card_probe,
+-      .remove = axg_card_remove,
++      .probe = meson_card_probe,
++      .remove = meson_card_remove,
+       .driver = {
+               .name = "axg-sound-card",
+               .of_match_table = axg_card_of_match,
+diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c
+new file mode 100644
+index 0000000000000..a70d244ef88b6
+--- /dev/null
++++ b/sound/soc/meson/meson-card-utils.c
+@@ -0,0 +1,385 @@
++// SPDX-License-Identifier: GPL-2.0
++//
++// Copyright (c) 2020 BayLibre, SAS.
++// Author: Jerome Brunet <jbrunet@baylibre.com>
++
++#include <linux/module.h>
++#include <linux/of_platform.h>
++#include <sound/soc.h>
++
++#include "meson-card.h"
++
++int meson_card_i2s_set_sysclk(struct snd_pcm_substream *substream,
++                            struct snd_pcm_hw_params *params,
++                            unsigned int mclk_fs)
++{
++      struct snd_soc_pcm_runtime *rtd = substream->private_data;
++      struct snd_soc_dai *codec_dai;
++      unsigned int mclk;
++      int ret, i;
++
++      if (!mclk_fs)
++              return 0;
++
++      mclk = params_rate(params) * mclk_fs;
++
++      for_each_rtd_codec_dai(rtd, i, codec_dai) {
++              ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
++                                           SND_SOC_CLOCK_IN);
++              if (ret && ret != -ENOTSUPP)
++                      return ret;
++      }
++
++      ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk,
++                                   SND_SOC_CLOCK_OUT);
++      if (ret && ret != -ENOTSUPP)
++              return ret;
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(meson_card_i2s_set_sysclk);
++
++int meson_card_reallocate_links(struct snd_soc_card *card,
++                              unsigned int num_links)
++{
++      struct meson_card *priv = snd_soc_card_get_drvdata(card);
++      struct snd_soc_dai_link *links;
++      void **ldata;
++
++      links = krealloc(priv->card.dai_link,
++                       num_links * sizeof(*priv->card.dai_link),
++                       GFP_KERNEL | __GFP_ZERO);
++      ldata = krealloc(priv->link_data,
++                       num_links * sizeof(*priv->link_data),
++                       GFP_KERNEL | __GFP_ZERO);
++
++      if (!links || !ldata) {
++              dev_err(priv->card.dev, "failed to allocate links\n");
++              return -ENOMEM;
++      }
++
++      priv->card.dai_link = links;
++      priv->link_data = ldata;
++      priv->card.num_links = num_links;
++      return 0;
++}
++EXPORT_SYMBOL_GPL(meson_card_reallocate_links);
++
++int meson_card_parse_dai(struct snd_soc_card *card,
++                       struct device_node *node,
++                       struct device_node **dai_of_node,
++                       const char **dai_name)
++{
++      struct of_phandle_args args;
++      int ret;
++
++      if (!dai_name || !dai_of_node || !node)
++              return -EINVAL;
++
++      ret = of_parse_phandle_with_args(node, "sound-dai",
++                                       "#sound-dai-cells", 0, &args);
++      if (ret) {
++              if (ret != -EPROBE_DEFER)
++                      dev_err(card->dev, "can't parse dai %d\n", ret);
++              return ret;
++      }
++      *dai_of_node = args.np;
++
++      return snd_soc_get_dai_name(&args, dai_name);
++}
++EXPORT_SYMBOL_GPL(meson_card_parse_dai);
++
++static int meson_card_set_link_name(struct snd_soc_card *card,
++                                  struct snd_soc_dai_link *link,
++                                  struct device_node *node,
++                                  const char *prefix)
++{
++      char *name = devm_kasprintf(card->dev, GFP_KERNEL, "%s.%s",
++                                  prefix, node->full_name);
++      if (!name)
++              return -ENOMEM;
++
++      link->name = name;
++      link->stream_name = name;
++
++      return 0;
++}
++
++unsigned int meson_card_parse_daifmt(struct device_node *node,
++                                   struct device_node *cpu_node)
++{
++      struct device_node *bitclkmaster = NULL;
++      struct device_node *framemaster = NULL;
++      unsigned int daifmt;
++
++      daifmt = snd_soc_of_parse_daifmt(node, DT_PREFIX,
++                                       &bitclkmaster, &framemaster);
++      daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
++
++      /* If no master is provided, default to cpu master */
++      if (!bitclkmaster || bitclkmaster == cpu_node) {
++              daifmt |= (!framemaster || framemaster == cpu_node) ?
++                      SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBS_CFM;
++      } else {
++              daifmt |= (!framemaster || framemaster == cpu_node) ?
++                      SND_SOC_DAIFMT_CBM_CFS : SND_SOC_DAIFMT_CBM_CFM;
++      }
++
++      of_node_put(bitclkmaster);
++      of_node_put(framemaster);
++
++      return daifmt;
++}
++EXPORT_SYMBOL_GPL(meson_card_parse_daifmt);
++
++int meson_card_set_be_link(struct snd_soc_card *card,
++                         struct snd_soc_dai_link *link,
++                         struct device_node *node)
++{
++      struct snd_soc_dai_link_component *codec;
++      struct device_node *np;
++      int ret, num_codecs;
++
++      link->no_pcm = 1;
++      link->dpcm_playback = 1;
++      link->dpcm_capture = 1;
++
++      num_codecs = of_get_child_count(node);
++      if (!num_codecs) {
++              dev_err(card->dev, "be link %s has no codec\n",
++                      node->full_name);
++              return -EINVAL;
++      }
++
++      codec = devm_kcalloc(card->dev, num_codecs, sizeof(*codec), GFP_KERNEL);
++      if (!codec)
++              return -ENOMEM;
++
++      link->codecs = codec;
++      link->num_codecs = num_codecs;
++
++      for_each_child_of_node(node, np) {
++              ret = meson_card_parse_dai(card, np, &codec->of_node,
++                                         &codec->dai_name);
++              if (ret) {
++                      of_node_put(np);
++                      return ret;
++              }
++
++              codec++;
++      }
++
++      ret = meson_card_set_link_name(card, link, node, "be");
++      if (ret)
++              dev_err(card->dev, "error setting %pOFn link name\n", np);
++
++      return ret;
++}
++EXPORT_SYMBOL_GPL(meson_card_set_be_link);
++
++int meson_card_set_fe_link(struct snd_soc_card *card,
++                         struct snd_soc_dai_link *link,
++                         struct device_node *node,
++                         bool is_playback)
++{
++      struct snd_soc_dai_link_component *codec;
++
++      codec = devm_kzalloc(card->dev, sizeof(*codec), GFP_KERNEL);
++      if (!codec)
++              return -ENOMEM;
++
++      link->codecs = codec;
++      link->num_codecs = 1;
++
++      link->dynamic = 1;
++      link->dpcm_merged_format = 1;
++      link->dpcm_merged_chan = 1;
++      link->dpcm_merged_rate = 1;
++      link->codecs->dai_name = "snd-soc-dummy-dai";
++      link->codecs->name = "snd-soc-dummy";
++
++      if (is_playback)
++              link->dpcm_playback = 1;
++      else
++              link->dpcm_capture = 1;
++
++      return meson_card_set_link_name(card, link, node, "fe");
++}
++EXPORT_SYMBOL_GPL(meson_card_set_fe_link);
++
++static int meson_card_add_links(struct snd_soc_card *card)
++{
++      struct meson_card *priv = snd_soc_card_get_drvdata(card);
++      struct device_node *node = card->dev->of_node;
++      struct device_node *np;
++      int num, i, ret;
++
++      num = of_get_child_count(node);
++      if (!num) {
++              dev_err(card->dev, "card has no links\n");
++              return -EINVAL;
++      }
++
++      ret = meson_card_reallocate_links(card, num);
++      if (ret)
++              return ret;
++
++      i = 0;
++      for_each_child_of_node(node, np) {
++              ret = priv->match_data->add_link(card, np, &i);
++              if (ret) {
++                      of_node_put(np);
++                      return ret;
++              }
++
++              i++;
++      }
++
++      return 0;
++}
++
++static int meson_card_parse_of_optional(struct snd_soc_card *card,
++                                      const char *propname,
++                                      int (*func)(struct snd_soc_card *c,
++                                                  const char *p))
++{
++      /* If property is not provided, don't fail ... */
++      if (!of_property_read_bool(card->dev->of_node, propname))
++              return 0;
++
++      /* ... but do fail if it is provided and the parsing fails */
++      return func(card, propname);
++}
++
++static int meson_card_add_aux_devices(struct snd_soc_card *card)
++{
++      struct device_node *node = card->dev->of_node;
++      struct snd_soc_aux_dev *aux;
++      int num, i;
++
++      num = of_count_phandle_with_args(node, "audio-aux-devs", NULL);
++      if (num == -ENOENT) {
++              return 0;
++      } else if (num < 0) {
++              dev_err(card->dev, "error getting auxiliary devices: %d\n",
++                      num);
++              return num;
++      }
++
++      aux = devm_kcalloc(card->dev, num, sizeof(*aux), GFP_KERNEL);
++      if (!aux)
++              return -ENOMEM;
++      card->aux_dev = aux;
++      card->num_aux_devs = num;
++
++      for_each_card_pre_auxs(card, i, aux) {
++              aux->dlc.of_node =
++                      of_parse_phandle(node, "audio-aux-devs", i);
++              if (!aux->dlc.of_node)
++                      return -EINVAL;
++      }
++
++      return 0;
++}
++
++static void meson_card_clean_references(struct meson_card *priv)
++{
++      struct snd_soc_card *card = &priv->card;
++      struct snd_soc_dai_link *link;
++      struct snd_soc_dai_link_component *codec;
++      struct snd_soc_aux_dev *aux;
++      int i, j;
++
++      if (card->dai_link) {
++              for_each_card_prelinks(card, i, link) {
++                      if (link->cpus)
++                              of_node_put(link->cpus->of_node);
++                      for_each_link_codecs(link, j, codec)
++                              of_node_put(codec->of_node);
++              }
++      }
++
++      if (card->aux_dev) {
++              for_each_card_pre_auxs(card, i, aux)
++                      of_node_put(aux->dlc.of_node);
++      }
++
++      kfree(card->dai_link);
++      kfree(priv->link_data);
++}
++
++int meson_card_probe(struct platform_device *pdev)
++{
++      const struct meson_card_match_data *data;
++      struct device *dev = &pdev->dev;
++      struct meson_card *priv;
++      int ret;
++
++      data = of_device_get_match_data(dev);
++      if (!data) {
++              dev_err(dev, "failed to match device\n");
++              return -ENODEV;
++      }
++
++      priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++
++      platform_set_drvdata(pdev, priv);
++      snd_soc_card_set_drvdata(&priv->card, priv);
++
++      priv->card.owner = THIS_MODULE;
++      priv->card.dev = dev;
++      priv->match_data = data;
++
++      ret = snd_soc_of_parse_card_name(&priv->card, "model");
++      if (ret < 0)
++              return ret;
++
++      ret = meson_card_parse_of_optional(&priv->card, "audio-routing",
++                                         snd_soc_of_parse_audio_routing);
++      if (ret) {
++              dev_err(dev, "error while parsing routing\n");
++              return ret;
++      }
++
++      ret = meson_card_parse_of_optional(&priv->card, "audio-widgets",
++                                         snd_soc_of_parse_audio_simple_widgets);
++      if (ret) {
++              dev_err(dev, "error while parsing widgets\n");
++              return ret;
++      }
++
++      ret = meson_card_add_links(&priv->card);
++      if (ret)
++              goto out_err;
++
++      ret = meson_card_add_aux_devices(&priv->card);
++      if (ret)
++              goto out_err;
++
++      ret = devm_snd_soc_register_card(dev, &priv->card);
++      if (ret)
++              goto out_err;
++
++      return 0;
++
++out_err:
++      meson_card_clean_references(priv);
++      return ret;
++}
++EXPORT_SYMBOL_GPL(meson_card_probe);
++
++int meson_card_remove(struct platform_device *pdev)
++{
++      struct meson_card *priv = platform_get_drvdata(pdev);
++
++      meson_card_clean_references(priv);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(meson_card_remove);
++
++MODULE_DESCRIPTION("Amlogic Sound Card Utils");
++MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
++MODULE_LICENSE("GPL v2");
+diff --git a/sound/soc/meson/meson-card.h b/sound/soc/meson/meson-card.h
+new file mode 100644
+index 0000000000000..74314071c80db
+--- /dev/null
++++ b/sound/soc/meson/meson-card.h
+@@ -0,0 +1,55 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (c) 2020 BayLibre, SAS.
++ * Author: Jerome Brunet <jbrunet@baylibre.com>
++ */
++
++#ifndef _MESON_SND_CARD_H
++#define _MESON_SND_CARD_H
++
++struct device_node;
++struct platform_device;
++
++struct snd_soc_card;
++struct snd_pcm_substream;
++struct snd_pcm_hw_params;
++
++#define DT_PREFIX "amlogic,"
++
++struct meson_card_match_data {
++      int (*add_link)(struct snd_soc_card *card,
++                      struct device_node *node,
++                      int *index);
++};
++
++struct meson_card {
++      const struct meson_card_match_data *match_data;
++      struct snd_soc_card card;
++      void **link_data;
++};
++
++unsigned int meson_card_parse_daifmt(struct device_node *node,
++                                   struct device_node *cpu_node);
++
++int meson_card_i2s_set_sysclk(struct snd_pcm_substream *substream,
++                            struct snd_pcm_hw_params *params,
++                            unsigned int mclk_fs);
++
++int meson_card_reallocate_links(struct snd_soc_card *card,
++                              unsigned int num_links);
++int meson_card_parse_dai(struct snd_soc_card *card,
++                       struct device_node *node,
++                       struct device_node **dai_of_node,
++                       const char **dai_name);
++int meson_card_set_be_link(struct snd_soc_card *card,
++                         struct snd_soc_dai_link *link,
++                         struct device_node *node);
++int meson_card_set_fe_link(struct snd_soc_card *card,
++                         struct snd_soc_dai_link *link,
++                         struct device_node *node,
++                         bool is_playback);
++
++int meson_card_probe(struct platform_device *pdev);
++int meson_card_remove(struct platform_device *pdev);
++
++#endif /* _MESON_SND_CARD_H */
+-- 
+2.43.0
+
diff --git a/queue-5.4/pci-xilinx-nwl-fix-off-by-one-in-intx-irq-handler.patch b/queue-5.4/pci-xilinx-nwl-fix-off-by-one-in-intx-irq-handler.patch
new file mode 100644 (file)
index 0000000..396883e
--- /dev/null
@@ -0,0 +1,73 @@
+From 4d4c4137bcf67176bf3ad6a1159f8e8ad7026494 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 May 2024 12:13:32 -0400
+Subject: PCI: xilinx-nwl: Fix off-by-one in INTx IRQ handler
+
+From: Sean Anderson <sean.anderson@linux.dev>
+
+[ Upstream commit 0199d2f2bd8cd97b310f7ed82a067247d7456029 ]
+
+MSGF_LEG_MASK is laid out with INTA in bit 0, INTB in bit 1, INTC in bit 2,
+and INTD in bit 3. Hardware IRQ numbers start at 0, and we register
+PCI_NUM_INTX IRQs. So to enable INTA (aka hwirq 0) we should set bit 0.
+Remove the subtraction of one.
+
+This bug would cause INTx interrupts not to be delivered, as enabling INTB
+would actually enable INTA, and enabling INTA wouldn't enable anything at
+all. It is likely that this got overlooked for so long since most PCIe
+hardware uses MSIs. This fixes the following UBSAN error:
+
+  UBSAN: shift-out-of-bounds in ../drivers/pci/controller/pcie-xilinx-nwl.c:389:11
+  shift exponent 18446744073709551615 is too large for 32-bit type 'int'
+  CPU: 1 PID: 61 Comm: kworker/u10:1 Not tainted 6.6.20+ #268
+  Hardware name: xlnx,zynqmp (DT)
+  Workqueue: events_unbound deferred_probe_work_func
+  Call trace:
+  dump_backtrace (arch/arm64/kernel/stacktrace.c:235)
+  show_stack (arch/arm64/kernel/stacktrace.c:242)
+  dump_stack_lvl (lib/dump_stack.c:107)
+  dump_stack (lib/dump_stack.c:114)
+  __ubsan_handle_shift_out_of_bounds (lib/ubsan.c:218 lib/ubsan.c:387)
+  nwl_unmask_leg_irq (drivers/pci/controller/pcie-xilinx-nwl.c:389 (discriminator 1))
+  irq_enable (kernel/irq/internals.h:234 kernel/irq/chip.c:170 kernel/irq/chip.c:439 kernel/irq/chip.c:432 kernel/irq/chip.c:345)
+  __irq_startup (kernel/irq/internals.h:239 kernel/irq/chip.c:180 kernel/irq/chip.c:250)
+  irq_startup (kernel/irq/chip.c:270)
+  __setup_irq (kernel/irq/manage.c:1800)
+  request_threaded_irq (kernel/irq/manage.c:2206)
+  pcie_pme_probe (include/linux/interrupt.h:168 drivers/pci/pcie/pme.c:348)
+
+Fixes: 9a181e1093af ("PCI: xilinx-nwl: Modify IRQ chip for legacy interrupts")
+Link: https://lore.kernel.org/r/20240531161337.864994-3-sean.anderson@linux.dev
+Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/pcie-xilinx-nwl.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pci/controller/pcie-xilinx-nwl.c b/drivers/pci/controller/pcie-xilinx-nwl.c
+index eb23bb28221a8..f08606f25e3c8 100644
+--- a/drivers/pci/controller/pcie-xilinx-nwl.c
++++ b/drivers/pci/controller/pcie-xilinx-nwl.c
+@@ -389,7 +389,7 @@ static void nwl_mask_leg_irq(struct irq_data *data)
+       u32 mask;
+       u32 val;
+-      mask = 1 << (data->hwirq - 1);
++      mask = 1 << data->hwirq;
+       raw_spin_lock_irqsave(&pcie->leg_mask_lock, flags);
+       val = nwl_bridge_readl(pcie, MSGF_LEG_MASK);
+       nwl_bridge_writel(pcie, (val & (~mask)), MSGF_LEG_MASK);
+@@ -403,7 +403,7 @@ static void nwl_unmask_leg_irq(struct irq_data *data)
+       u32 mask;
+       u32 val;
+-      mask = 1 << (data->hwirq - 1);
++      mask = 1 << data->hwirq;
+       raw_spin_lock_irqsave(&pcie->leg_mask_lock, flags);
+       val = nwl_bridge_readl(pcie, MSGF_LEG_MASK);
+       nwl_bridge_writel(pcie, (val | mask), MSGF_LEG_MASK);
+-- 
+2.43.0
+
diff --git a/queue-5.4/pci-xilinx-nwl-use-irq_data_get_irq_chip_data.patch b/queue-5.4/pci-xilinx-nwl-use-irq_data_get_irq_chip_data.patch
new file mode 100644 (file)
index 0000000..4ab306c
--- /dev/null
@@ -0,0 +1,65 @@
+From 0aeb45562ba3a342fb9c2f56f3e50e9c2d9171cf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 10 Dec 2020 20:25:54 +0100
+Subject: PCI: xilinx-nwl: Use irq_data_get_irq_chip_data()
+
+From: Thomas Gleixner <tglx@linutronix.de>
+
+[ Upstream commit e56427068a8d796bb7b8e297f2b6e947380e383f ]
+
+Going through a full irq descriptor lookup instead of just using the proper
+helper function which provides direct access is suboptimal.
+
+In fact it _is_ wrong because the chip callback needs to get the chip data
+which is relevant for the chip while using the irq descriptor variant
+returns the irq chip data of the top level chip of a hierarchy. It does not
+matter in this case because the chip is the top level chip, but that
+doesn't make it more correct.
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Cc: Bjorn Helgaas <bhelgaas@google.com>
+Link: https://lore.kernel.org/r/20201210194044.364211860@linutronix.de
+Stable-dep-of: 0199d2f2bd8c ("PCI: xilinx-nwl: Fix off-by-one in INTx IRQ handler")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/pcie-xilinx-nwl.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/pci/controller/pcie-xilinx-nwl.c b/drivers/pci/controller/pcie-xilinx-nwl.c
+index 539bf53beb654..eb23bb28221a8 100644
+--- a/drivers/pci/controller/pcie-xilinx-nwl.c
++++ b/drivers/pci/controller/pcie-xilinx-nwl.c
+@@ -384,13 +384,11 @@ static void nwl_pcie_msi_handler_low(struct irq_desc *desc)
+ static void nwl_mask_leg_irq(struct irq_data *data)
+ {
+-      struct irq_desc *desc = irq_to_desc(data->irq);
+-      struct nwl_pcie *pcie;
++      struct nwl_pcie *pcie = irq_data_get_irq_chip_data(data);
+       unsigned long flags;
+       u32 mask;
+       u32 val;
+-      pcie = irq_desc_get_chip_data(desc);
+       mask = 1 << (data->hwirq - 1);
+       raw_spin_lock_irqsave(&pcie->leg_mask_lock, flags);
+       val = nwl_bridge_readl(pcie, MSGF_LEG_MASK);
+@@ -400,13 +398,11 @@ static void nwl_mask_leg_irq(struct irq_data *data)
+ static void nwl_unmask_leg_irq(struct irq_data *data)
+ {
+-      struct irq_desc *desc = irq_to_desc(data->irq);
+-      struct nwl_pcie *pcie;
++      struct nwl_pcie *pcie = irq_data_get_irq_chip_data(data);
+       unsigned long flags;
+       u32 mask;
+       u32 val;
+-      pcie = irq_desc_get_chip_data(desc);
+       mask = 1 << (data->hwirq - 1);
+       raw_spin_lock_irqsave(&pcie->leg_mask_lock, flags);
+       val = nwl_bridge_readl(pcie, MSGF_LEG_MASK);
+-- 
+2.43.0
+
diff --git a/queue-5.4/pps-add-an-error-check-in-parport_attach.patch b/queue-5.4/pps-add-an-error-check-in-parport_attach.patch
new file mode 100644 (file)
index 0000000..5e87b8d
--- /dev/null
@@ -0,0 +1,65 @@
+From 55a0aa62eba90973cdd0ef048db3143695cd07f7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 28 Aug 2024 21:18:14 +0800
+Subject: pps: add an error check in parport_attach
+
+From: Ma Ke <make24@iscas.ac.cn>
+
+[ Upstream commit 62c5a01a5711c8e4be8ae7b6f0db663094615d48 ]
+
+In parport_attach, the return value of ida_alloc is unchecked, witch leads
+to the use of an invalid index value.
+
+To address this issue, index should be checked. When the index value is
+abnormal, the device should be freed.
+
+Found by code review, compile tested only.
+
+Cc: stable@vger.kernel.org
+Fixes: fb56d97df70e ("pps: client: use new parport device model")
+Signed-off-by: Ma Ke <make24@iscas.ac.cn>
+Acked-by: Rodolfo Giometti <giometti@enneenne.com>
+Link: https://lore.kernel.org/r/20240828131814.3034338-1-make24@iscas.ac.cn
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pps/clients/pps_parport.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pps/clients/pps_parport.c b/drivers/pps/clients/pps_parport.c
+index 4bb3678c7e451..84e49204912f8 100644
+--- a/drivers/pps/clients/pps_parport.c
++++ b/drivers/pps/clients/pps_parport.c
+@@ -145,6 +145,9 @@ static void parport_attach(struct parport *port)
+       }
+       index = ida_alloc(&pps_client_index, GFP_KERNEL);
++      if (index < 0)
++              goto err_free_device;
++
+       memset(&pps_client_cb, 0, sizeof(pps_client_cb));
+       pps_client_cb.private = device;
+       pps_client_cb.irq_func = parport_irq;
+@@ -155,7 +158,7 @@ static void parport_attach(struct parport *port)
+                                                   index);
+       if (!device->pardev) {
+               pr_err("couldn't register with %s\n", port->name);
+-              goto err_free;
++              goto err_free_ida;
+       }
+       if (parport_claim_or_block(device->pardev) < 0) {
+@@ -183,8 +186,9 @@ static void parport_attach(struct parport *port)
+       parport_release(device->pardev);
+ err_unregister_dev:
+       parport_unregister_device(device->pardev);
+-err_free:
++err_free_ida:
+       ida_free(&pps_client_index, index);
++err_free_device:
+       kfree(device);
+ }
+-- 
+2.43.0
+
diff --git a/queue-5.4/pps-remove-usage-of-the-deprecated-ida_simple_xx-api.patch b/queue-5.4/pps-remove-usage-of-the-deprecated-ida_simple_xx-api.patch
new file mode 100644 (file)
index 0000000..aaf8958
--- /dev/null
@@ -0,0 +1,59 @@
+From 2d180419cba909b0ea76c6b99431e0e0347200a9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 14 Apr 2024 12:10:17 +0200
+Subject: pps: remove usage of the deprecated ida_simple_xx() API
+
+From: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+
+[ Upstream commit 55dbc5b5174d0e7d1fa397d05aa4cb145e8b887e ]
+
+ida_alloc() and ida_free() should be preferred to the deprecated
+ida_simple_get() and ida_simple_remove().
+
+This is less verbose.
+
+Link: https://lkml.kernel.org/r/9f681747d446b874952a892491387d79ffe565a9.1713089394.git.christophe.jaillet@wanadoo.fr
+Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+Cc: Rodolfo Giometti <giometti@enneenne.com>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Stable-dep-of: 62c5a01a5711 ("pps: add an error check in parport_attach")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pps/clients/pps_parport.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/pps/clients/pps_parport.c b/drivers/pps/clients/pps_parport.c
+index 7a41fb7b0decf..4bb3678c7e451 100644
+--- a/drivers/pps/clients/pps_parport.c
++++ b/drivers/pps/clients/pps_parport.c
+@@ -144,7 +144,7 @@ static void parport_attach(struct parport *port)
+               return;
+       }
+-      index = ida_simple_get(&pps_client_index, 0, 0, GFP_KERNEL);
++      index = ida_alloc(&pps_client_index, GFP_KERNEL);
+       memset(&pps_client_cb, 0, sizeof(pps_client_cb));
+       pps_client_cb.private = device;
+       pps_client_cb.irq_func = parport_irq;
+@@ -184,7 +184,7 @@ static void parport_attach(struct parport *port)
+ err_unregister_dev:
+       parport_unregister_device(device->pardev);
+ err_free:
+-      ida_simple_remove(&pps_client_index, index);
++      ida_free(&pps_client_index, index);
+       kfree(device);
+ }
+@@ -204,7 +204,7 @@ static void parport_detach(struct parport *port)
+       pps_unregister_source(device->pps);
+       parport_release(pardev);
+       parport_unregister_device(pardev);
+-      ida_simple_remove(&pps_client_index, device->index);
++      ida_free(&pps_client_index, device->index);
+       kfree(device);
+ }
+-- 
+2.43.0
+
index def9f6c2a8c83560c7667ec66fcfe0c593067211..f3556daf917d8035d245718376b414bfcd3e2862 100644 (file)
@@ -162,3 +162,13 @@ hwrng-mtk-use-devm_pm_runtime_enable.patch
 vfs-fix-race-between-evice_inodes-and-find_inode-iput.patch
 fs-fix-file_set_fowner-lsm-hook-inconsistencies.patch
 nfs-fix-memory-leak-in-error-path-of-nfs4_do_reclaim.patch
+asoc-meson-axg-extract-sound-card-utils.patch
+asoc-meson-axg-card-fix-use-after-free.patch
+pci-xilinx-nwl-use-irq_data_get_irq_chip_data.patch
+pci-xilinx-nwl-fix-off-by-one-in-intx-irq-handler.patch
+soc-versatile-realview-fix-memory-leak-during-device.patch
+soc-versatile-realview-fix-soc_dev-leak-during-devic.patch
+usb-yurex-replace-snprintf-with-the-safer-scnprintf-.patch
+usb-misc-yurex-fix-race-between-read-and-write.patch
+pps-remove-usage-of-the-deprecated-ida_simple_xx-api.patch
+pps-add-an-error-check-in-parport_attach.patch
diff --git a/queue-5.4/soc-versatile-realview-fix-memory-leak-during-device.patch b/queue-5.4/soc-versatile-realview-fix-memory-leak-during-device.patch
new file mode 100644 (file)
index 0000000..1a96e9d
--- /dev/null
@@ -0,0 +1,50 @@
+From 203806e5541d52c2f1a475d3120012ba6dac54d8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 25 Aug 2024 20:05:23 +0200
+Subject: soc: versatile: realview: fix memory leak during device remove
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 1c4f26a41f9d052f334f6ae629e01f598ed93508 ]
+
+If device is unbound, the memory allocated for soc_dev_attr should be
+freed to prevent leaks.
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://lore.kernel.org/20240825-soc-dev-fixes-v1-2-ff4b35abed83@linaro.org
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Stable-dep-of: c774f2564c00 ("soc: versatile: realview: fix soc_dev leak during device remove")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/versatile/soc-realview.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/soc/versatile/soc-realview.c b/drivers/soc/versatile/soc-realview.c
+index 9471353dd8c38..60947a5161e4c 100644
+--- a/drivers/soc/versatile/soc-realview.c
++++ b/drivers/soc/versatile/soc-realview.c
+@@ -91,7 +91,7 @@ static int realview_soc_probe(struct platform_device *pdev)
+       if (IS_ERR(syscon_regmap))
+               return PTR_ERR(syscon_regmap);
+-      soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
++      soc_dev_attr = devm_kzalloc(&pdev->dev, sizeof(*soc_dev_attr), GFP_KERNEL);
+       if (!soc_dev_attr)
+               return -ENOMEM;
+@@ -103,10 +103,9 @@ static int realview_soc_probe(struct platform_device *pdev)
+       soc_dev_attr->machine = "RealView";
+       soc_dev_attr->family = "Versatile";
+       soc_dev = soc_device_register(soc_dev_attr);
+-      if (IS_ERR(soc_dev)) {
+-              kfree(soc_dev_attr);
++      if (IS_ERR(soc_dev))
+               return -ENODEV;
+-      }
++
+       ret = regmap_read(syscon_regmap, REALVIEW_SYS_ID_OFFSET,
+                         &realview_coreid);
+       if (ret)
+-- 
+2.43.0
+
diff --git a/queue-5.4/soc-versatile-realview-fix-soc_dev-leak-during-devic.patch b/queue-5.4/soc-versatile-realview-fix-soc_dev-leak-during-devic.patch
new file mode 100644 (file)
index 0000000..961af7c
--- /dev/null
@@ -0,0 +1,63 @@
+From 20df9af892df09028517f4da01af278b7c16ea4c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 25 Aug 2024 20:05:24 +0200
+Subject: soc: versatile: realview: fix soc_dev leak during device remove
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit c774f2564c0086c23f5269fd4691f233756bf075 ]
+
+If device is unbound, the soc_dev should be unregistered to prevent
+memory leak.
+
+Fixes: a2974c9c1f83 ("soc: add driver for the ARM RealView")
+Cc: stable@vger.kernel.org
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://lore.kernel.org/20240825-soc-dev-fixes-v1-3-ff4b35abed83@linaro.org
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/versatile/soc-realview.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/drivers/soc/versatile/soc-realview.c b/drivers/soc/versatile/soc-realview.c
+index 60947a5161e4c..9cddbde399860 100644
+--- a/drivers/soc/versatile/soc-realview.c
++++ b/drivers/soc/versatile/soc-realview.c
+@@ -4,6 +4,7 @@
+  *
+  * Author: Linus Walleij <linus.walleij@linaro.org>
+  */
++#include <linux/device.h>
+ #include <linux/init.h>
+ #include <linux/io.h>
+ #include <linux/slab.h>
+@@ -79,6 +80,13 @@ static ssize_t realview_get_build(struct device *dev,
+ static struct device_attribute realview_build_attr =
+       __ATTR(build,  S_IRUGO, realview_get_build,  NULL);
++static void realview_soc_socdev_release(void *data)
++{
++      struct soc_device *soc_dev = data;
++
++      soc_device_unregister(soc_dev);
++}
++
+ static int realview_soc_probe(struct platform_device *pdev)
+ {
+       struct regmap *syscon_regmap;
+@@ -106,6 +114,11 @@ static int realview_soc_probe(struct platform_device *pdev)
+       if (IS_ERR(soc_dev))
+               return -ENODEV;
++      ret = devm_add_action_or_reset(&pdev->dev, realview_soc_socdev_release,
++                                     soc_dev);
++      if (ret)
++              return ret;
++
+       ret = regmap_read(syscon_regmap, REALVIEW_SYS_ID_OFFSET,
+                         &realview_coreid);
+       if (ret)
+-- 
+2.43.0
+
diff --git a/queue-5.4/usb-misc-yurex-fix-race-between-read-and-write.patch b/queue-5.4/usb-misc-yurex-fix-race-between-read-and-write.patch
new file mode 100644 (file)
index 0000000..c581ef3
--- /dev/null
@@ -0,0 +1,63 @@
+From eca18fcac1723b0c8c9c52e1985ab22e3e117994 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Sep 2024 15:21:22 +0200
+Subject: USB: misc: yurex: fix race between read and write
+
+From: Oliver Neukum <oneukum@suse.com>
+
+[ Upstream commit 93907620b308609c72ba4b95b09a6aa2658bb553 ]
+
+The write code path touches the bbu member in a non atomic manner
+without taking the spinlock. Fix it.
+
+The bug is as old as the driver.
+
+Signed-off-by: Oliver Neukum <oneukum@suse.com>
+CC: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20240912132126.1034743-1-oneukum@suse.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/misc/yurex.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
+index a85cc0f3e15c4..5f271d25b633d 100644
+--- a/drivers/usb/misc/yurex.c
++++ b/drivers/usb/misc/yurex.c
+@@ -405,7 +405,6 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
+       struct usb_yurex *dev;
+       int len = 0;
+       char in_buffer[MAX_S64_STRLEN];
+-      unsigned long flags;
+       dev = file->private_data;
+@@ -418,9 +417,9 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
+       if (WARN_ON_ONCE(dev->bbu > S64_MAX || dev->bbu < S64_MIN))
+               return -EIO;
+-      spin_lock_irqsave(&dev->lock, flags);
++      spin_lock_irq(&dev->lock);
+       scnprintf(in_buffer, MAX_S64_STRLEN, "%lld\n", dev->bbu);
+-      spin_unlock_irqrestore(&dev->lock, flags);
++      spin_unlock_irq(&dev->lock);
+       mutex_unlock(&dev->io_mutex);
+       return simple_read_from_buffer(buffer, count, ppos, in_buffer, len);
+@@ -510,8 +509,11 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer,
+                       __func__, retval);
+               goto error;
+       }
+-      if (set && timeout)
++      if (set && timeout) {
++              spin_lock_irq(&dev->lock);
+               dev->bbu = c2;
++              spin_unlock_irq(&dev->lock);
++      }
+       return timeout ? count : -EIO;
+ error:
+-- 
+2.43.0
+
diff --git a/queue-5.4/usb-yurex-replace-snprintf-with-the-safer-scnprintf-.patch b/queue-5.4/usb-yurex-replace-snprintf-with-the-safer-scnprintf-.patch
new file mode 100644 (file)
index 0000000..573360b
--- /dev/null
@@ -0,0 +1,77 @@
+From b9ba8d303cd07fa3e2ac6f412edce866f497fda6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 Dec 2023 16:42:37 +0000
+Subject: usb: yurex: Replace snprintf() with the safer scnprintf() variant
+
+From: Lee Jones <lee@kernel.org>
+
+[ Upstream commit 86b20af11e84c26ae3fde4dcc4f490948e3f8035 ]
+
+There is a general misunderstanding amongst engineers that {v}snprintf()
+returns the length of the data *actually* encoded into the destination
+array.  However, as per the C99 standard {v}snprintf() really returns
+the length of the data that *would have been* written if there were
+enough space for it.  This misunderstanding has led to buffer-overruns
+in the past.  It's generally considered safer to use the {v}scnprintf()
+variants in their place (or even sprintf() in simple cases).  So let's
+do that.
+
+Whilst we're at it, let's define some magic numbers to increase
+readability and ease of maintenance.
+
+Link: https://lwn.net/Articles/69419/
+Link: https://github.com/KSPP/linux/issues/105
+Cc: Tomoki Sekiyama <tomoki.sekiyama@gmail.com>
+Signed-off-by: Lee Jones <lee@kernel.org>
+Link: https://lore.kernel.org/r/20231213164246.1021885-9-lee@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 93907620b308 ("USB: misc: yurex: fix race between read and write")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/misc/yurex.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
+index 08b72bb22b7ef..a85cc0f3e15c4 100644
+--- a/drivers/usb/misc/yurex.c
++++ b/drivers/usb/misc/yurex.c
+@@ -34,6 +34,8 @@
+ #define YUREX_BUF_SIZE                8
+ #define YUREX_WRITE_TIMEOUT   (HZ*2)
++#define MAX_S64_STRLEN 20 /* {-}922337203685477580{7,8} */
++
+ /* table of devices that work with this driver */
+ static struct usb_device_id yurex_table[] = {
+       { USB_DEVICE(YUREX_VENDOR_ID, YUREX_PRODUCT_ID) },
+@@ -402,7 +404,7 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
+ {
+       struct usb_yurex *dev;
+       int len = 0;
+-      char in_buffer[20];
++      char in_buffer[MAX_S64_STRLEN];
+       unsigned long flags;
+       dev = file->private_data;
+@@ -413,14 +415,14 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
+               return -ENODEV;
+       }
++      if (WARN_ON_ONCE(dev->bbu > S64_MAX || dev->bbu < S64_MIN))
++              return -EIO;
++
+       spin_lock_irqsave(&dev->lock, flags);
+-      len = snprintf(in_buffer, 20, "%lld\n", dev->bbu);
++      scnprintf(in_buffer, MAX_S64_STRLEN, "%lld\n", dev->bbu);
+       spin_unlock_irqrestore(&dev->lock, flags);
+       mutex_unlock(&dev->io_mutex);
+-      if (WARN_ON_ONCE(len >= sizeof(in_buffer)))
+-              return -EIO;
+-
+       return simple_read_from_buffer(buffer, count, ppos, in_buffer, len);
+ }
+-- 
+2.43.0
+