]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 6.7
authorSasha Levin <sashal@kernel.org>
Thu, 7 Mar 2024 16:56:25 +0000 (11:56 -0500)
committerSasha Levin <sashal@kernel.org>
Thu, 7 Mar 2024 16:56:25 +0000 (11:56 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-6.7/dmaengine-fsl-edma-correct-max_segment_size-setting.patch [new file with mode: 0644]
queue-6.7/dmaengine-fsl-edma-utilize-common-dt-binding-header-.patch [new file with mode: 0644]
queue-6.7/drm-bridge-add-transparent-bridge-helper.patch [new file with mode: 0644]
queue-6.7/drm-bridge-aux-hpd-separate-allocation-and-registrat.patch [new file with mode: 0644]
queue-6.7/drm-bridge-implement-generic-dp-hpd-bridge.patch [new file with mode: 0644]
queue-6.7/dt-bindings-dma-fsl-edma-add-fsl-edma.h-to-prevent-h.patch [new file with mode: 0644]
queue-6.7/series [new file with mode: 0644]
queue-6.7/soc-qcom-pmic-glink-switch-to-drm_aux_hpd_bridge.patch [new file with mode: 0644]
queue-6.7/soc-qcom-pmic_glink_altmode-fix-drm-bridge-use-after.patch [new file with mode: 0644]

diff --git a/queue-6.7/dmaengine-fsl-edma-correct-max_segment_size-setting.patch b/queue-6.7/dmaengine-fsl-edma-correct-max_segment_size-setting.patch
new file mode 100644 (file)
index 0000000..bd4aa8c
--- /dev/null
@@ -0,0 +1,66 @@
+From 6460f2928f75e0db6289f78ff562d4b566193b7b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 7 Feb 2024 14:47:32 -0500
+Subject: dmaengine: fsl-edma: correct max_segment_size setting
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit a79f949a5ce1d45329d63742c2a995f2b47f9852 ]
+
+Correcting the previous setting of 0x3fff to the actual value of 0x7fff.
+
+Introduced new macro 'EDMA_TCD_ITER_MASK' for improved code clarity and
+utilization of FIELD_GET to obtain the accurate maximum value.
+
+Cc: stable@vger.kernel.org
+Fixes: e06748539432 ("dmaengine: fsl-edma: support edma memcpy")
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Link: https://lore.kernel.org/r/20240207194733.2112870-1-Frank.Li@nxp.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/dma/fsl-edma-common.h | 5 +++--
+ drivers/dma/fsl-edma-main.c   | 4 +++-
+ 2 files changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h
+index bb5221158a770..f5e216b157c75 100644
+--- a/drivers/dma/fsl-edma-common.h
++++ b/drivers/dma/fsl-edma-common.h
+@@ -30,8 +30,9 @@
+ #define EDMA_TCD_ATTR_SSIZE(x)                (((x) & GENMASK(2, 0)) << 8)
+ #define EDMA_TCD_ATTR_SMOD(x)         (((x) & GENMASK(4, 0)) << 11)
+-#define EDMA_TCD_CITER_CITER(x)               ((x) & GENMASK(14, 0))
+-#define EDMA_TCD_BITER_BITER(x)               ((x) & GENMASK(14, 0))
++#define EDMA_TCD_ITER_MASK            GENMASK(14, 0)
++#define EDMA_TCD_CITER_CITER(x)               ((x) & EDMA_TCD_ITER_MASK)
++#define EDMA_TCD_BITER_BITER(x)               ((x) & EDMA_TCD_ITER_MASK)
+ #define EDMA_TCD_CSR_START            BIT(0)
+ #define EDMA_TCD_CSR_INT_MAJOR                BIT(1)
+diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c
+index 45cc419b1b4ac..d36e28b9c767a 100644
+--- a/drivers/dma/fsl-edma-main.c
++++ b/drivers/dma/fsl-edma-main.c
+@@ -10,6 +10,7 @@
+  */
+ #include <dt-bindings/dma/fsl-edma.h>
++#include <linux/bitfield.h>
+ #include <linux/module.h>
+ #include <linux/interrupt.h>
+ #include <linux/clk.h>
+@@ -582,7 +583,8 @@ static int fsl_edma_probe(struct platform_device *pdev)
+                                       DMAENGINE_ALIGN_32_BYTES;
+       /* Per worst case 'nbytes = 1' take CITER as the max_seg_size */
+-      dma_set_max_seg_size(fsl_edma->dma_dev.dev, 0x3fff);
++      dma_set_max_seg_size(fsl_edma->dma_dev.dev,
++                           FIELD_GET(EDMA_TCD_ITER_MASK, EDMA_TCD_ITER_MASK));
+       fsl_edma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
+-- 
+2.43.0
+
diff --git a/queue-6.7/dmaengine-fsl-edma-utilize-common-dt-binding-header-.patch b/queue-6.7/dmaengine-fsl-edma-utilize-common-dt-binding-header-.patch
new file mode 100644 (file)
index 0000000..97a0495
--- /dev/null
@@ -0,0 +1,69 @@
+From ec7dd0a2ede3646cd4ef01d0026d36bd8f7bfb53 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Nov 2023 10:48:23 -0500
+Subject: dmaengine: fsl-edma: utilize common dt-binding header file
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit d0e217b72f9f5c5ef35e3423d393ea8093ce98ec ]
+
+Refactor the code to use the common dt-binding header file, fsl-edma.h.
+Renaming ARGS* to FSL_EDMA*, ensuring no functional changes.
+
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Link: https://lore.kernel.org/r/20231114154824.3617255-4-Frank.Li@nxp.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Stable-dep-of: a79f949a5ce1 ("dmaengine: fsl-edma: correct max_segment_size setting")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/dma/fsl-edma-main.c | 17 ++++++-----------
+ 1 file changed, 6 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c
+index 75cae7ccae270..45cc419b1b4ac 100644
+--- a/drivers/dma/fsl-edma-main.c
++++ b/drivers/dma/fsl-edma-main.c
+@@ -9,6 +9,7 @@
+  * Vybrid and Layerscape SoCs.
+  */
++#include <dt-bindings/dma/fsl-edma.h>
+ #include <linux/module.h>
+ #include <linux/interrupt.h>
+ #include <linux/clk.h>
+@@ -21,12 +22,6 @@
+ #include "fsl-edma-common.h"
+-#define ARGS_RX                         BIT(0)
+-#define ARGS_REMOTE                     BIT(1)
+-#define ARGS_MULTI_FIFO                 BIT(2)
+-#define ARGS_EVEN_CH                    BIT(3)
+-#define ARGS_ODD_CH                     BIT(4)
+-
+ static void fsl_edma_synchronize(struct dma_chan *chan)
+ {
+       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+@@ -155,14 +150,14 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec,
+               i = fsl_chan - fsl_edma->chans;
+               fsl_chan->priority = dma_spec->args[1];
+-              fsl_chan->is_rxchan = dma_spec->args[2] & ARGS_RX;
+-              fsl_chan->is_remote = dma_spec->args[2] & ARGS_REMOTE;
+-              fsl_chan->is_multi_fifo = dma_spec->args[2] & ARGS_MULTI_FIFO;
++              fsl_chan->is_rxchan = dma_spec->args[2] & FSL_EDMA_RX;
++              fsl_chan->is_remote = dma_spec->args[2] & FSL_EDMA_REMOTE;
++              fsl_chan->is_multi_fifo = dma_spec->args[2] & FSL_EDMA_MULTI_FIFO;
+-              if ((dma_spec->args[2] & ARGS_EVEN_CH) && (i & 0x1))
++              if ((dma_spec->args[2] & FSL_EDMA_EVEN_CH) && (i & 0x1))
+                       continue;
+-              if ((dma_spec->args[2] & ARGS_ODD_CH) && !(i & 0x1))
++              if ((dma_spec->args[2] & FSL_EDMA_ODD_CH) && !(i & 0x1))
+                       continue;
+               if (!b_chmux && i == dma_spec->args[0]) {
+-- 
+2.43.0
+
diff --git a/queue-6.7/drm-bridge-add-transparent-bridge-helper.patch b/queue-6.7/drm-bridge-add-transparent-bridge-helper.patch
new file mode 100644 (file)
index 0000000..3932022
--- /dev/null
@@ -0,0 +1,233 @@
+From 17e9df4c7836d0de0a085dca309eba6b7a2c2747 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 3 Dec 2023 14:43:28 +0300
+Subject: drm/bridge: add transparent bridge helper
+
+From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+
+[ Upstream commit 2a04739139b2b2761571e18937e2400e71eff664 ]
+
+Define a helper for creating simple transparent bridges which serve the
+only purpose of linking devices into the bridge chain up to the last
+bridge representing the connector. This is especially useful for
+DP/USB-C bridge chains, which can span across several devices, but do
+not require any additional functionality from the intermediate bridges.
+
+Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Link: https://patchwork.freedesktop.org/patch/msgid/20231203114333.1305826-2-dmitry.baryshkov@linaro.org
+Stable-dep-of: b979f2d50a09 ("soc: qcom: pmic_glink_altmode: fix drm bridge use-after-free")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/bridge/Kconfig      |   9 ++
+ drivers/gpu/drm/bridge/Makefile     |   1 +
+ drivers/gpu/drm/bridge/aux-bridge.c | 140 ++++++++++++++++++++++++++++
+ include/drm/bridge/aux-bridge.h     |  19 ++++
+ 4 files changed, 169 insertions(+)
+ create mode 100644 drivers/gpu/drm/bridge/aux-bridge.c
+ create mode 100644 include/drm/bridge/aux-bridge.h
+
+diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
+index 3e6a4e2044c0e..a22645efe93a0 100644
+--- a/drivers/gpu/drm/bridge/Kconfig
++++ b/drivers/gpu/drm/bridge/Kconfig
+@@ -12,6 +12,15 @@ config DRM_PANEL_BRIDGE
+       help
+         DRM bridge wrapper of DRM panels
++config DRM_AUX_BRIDGE
++      tristate
++      depends on DRM_BRIDGE && OF
++      select AUXILIARY_BUS
++      select DRM_PANEL_BRIDGE
++      help
++        Simple transparent bridge that is used by several non-DRM drivers to
++        build bridges chain.
++
+ menu "Display Interface Bridges"
+       depends on DRM && DRM_BRIDGE
+diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
+index 2b892b7ed59e8..918e3bfff079c 100644
+--- a/drivers/gpu/drm/bridge/Makefile
++++ b/drivers/gpu/drm/bridge/Makefile
+@@ -1,4 +1,5 @@
+ # SPDX-License-Identifier: GPL-2.0
++obj-$(CONFIG_DRM_AUX_BRIDGE) += aux-bridge.o
+ obj-$(CONFIG_DRM_CHIPONE_ICN6211) += chipone-icn6211.o
+ obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
+ obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o
+diff --git a/drivers/gpu/drm/bridge/aux-bridge.c b/drivers/gpu/drm/bridge/aux-bridge.c
+new file mode 100644
+index 0000000000000..49d7c2ab1ecc3
+--- /dev/null
++++ b/drivers/gpu/drm/bridge/aux-bridge.c
+@@ -0,0 +1,140 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2023 Linaro Ltd.
++ *
++ * Author: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
++ */
++#include <linux/auxiliary_bus.h>
++#include <linux/module.h>
++
++#include <drm/drm_bridge.h>
++#include <drm/bridge/aux-bridge.h>
++
++static DEFINE_IDA(drm_aux_bridge_ida);
++
++static void drm_aux_bridge_release(struct device *dev)
++{
++      struct auxiliary_device *adev = to_auxiliary_dev(dev);
++
++      ida_free(&drm_aux_bridge_ida, adev->id);
++
++      kfree(adev);
++}
++
++static void drm_aux_bridge_unregister_adev(void *_adev)
++{
++      struct auxiliary_device *adev = _adev;
++
++      auxiliary_device_delete(adev);
++      auxiliary_device_uninit(adev);
++}
++
++/**
++ * drm_aux_bridge_register - Create a simple bridge device to link the chain
++ * @parent: device instance providing this bridge
++ *
++ * Creates a simple DRM bridge that doesn't implement any drm_bridge
++ * operations. Such bridges merely fill a place in the bridge chain linking
++ * surrounding DRM bridges.
++ *
++ * Return: zero on success, negative error code on failure
++ */
++int drm_aux_bridge_register(struct device *parent)
++{
++      struct auxiliary_device *adev;
++      int ret;
++
++      adev = kzalloc(sizeof(*adev), GFP_KERNEL);
++      if (!adev)
++              return -ENOMEM;
++
++      ret = ida_alloc(&drm_aux_bridge_ida, GFP_KERNEL);
++      if (ret < 0) {
++              kfree(adev);
++              return ret;
++      }
++
++      adev->id = ret;
++      adev->name = "aux_bridge";
++      adev->dev.parent = parent;
++      adev->dev.of_node = parent->of_node;
++      adev->dev.release = drm_aux_bridge_release;
++
++      ret = auxiliary_device_init(adev);
++      if (ret) {
++              ida_free(&drm_aux_bridge_ida, adev->id);
++              kfree(adev);
++              return ret;
++      }
++
++      ret = auxiliary_device_add(adev);
++      if (ret) {
++              auxiliary_device_uninit(adev);
++              return ret;
++      }
++
++      return devm_add_action_or_reset(parent, drm_aux_bridge_unregister_adev, adev);
++}
++EXPORT_SYMBOL_GPL(drm_aux_bridge_register);
++
++struct drm_aux_bridge_data {
++      struct drm_bridge bridge;
++      struct drm_bridge *next_bridge;
++      struct device *dev;
++};
++
++static int drm_aux_bridge_attach(struct drm_bridge *bridge,
++                               enum drm_bridge_attach_flags flags)
++{
++      struct drm_aux_bridge_data *data;
++
++      if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
++              return -EINVAL;
++
++      data = container_of(bridge, struct drm_aux_bridge_data, bridge);
++
++      return drm_bridge_attach(bridge->encoder, data->next_bridge, bridge,
++                               DRM_BRIDGE_ATTACH_NO_CONNECTOR);
++}
++
++static const struct drm_bridge_funcs drm_aux_bridge_funcs = {
++      .attach = drm_aux_bridge_attach,
++};
++
++static int drm_aux_bridge_probe(struct auxiliary_device *auxdev,
++                              const struct auxiliary_device_id *id)
++{
++      struct drm_aux_bridge_data *data;
++
++      data = devm_kzalloc(&auxdev->dev, sizeof(*data), GFP_KERNEL);
++      if (!data)
++              return -ENOMEM;
++
++      data->dev = &auxdev->dev;
++      data->next_bridge = devm_drm_of_get_bridge(&auxdev->dev, auxdev->dev.of_node, 0, 0);
++      if (IS_ERR(data->next_bridge))
++              return dev_err_probe(&auxdev->dev, PTR_ERR(data->next_bridge),
++                                   "failed to acquire drm_bridge\n");
++
++      data->bridge.funcs = &drm_aux_bridge_funcs;
++      data->bridge.of_node = data->dev->of_node;
++
++      return devm_drm_bridge_add(data->dev, &data->bridge);
++}
++
++static const struct auxiliary_device_id drm_aux_bridge_table[] = {
++      { .name = KBUILD_MODNAME ".aux_bridge" },
++      {},
++};
++MODULE_DEVICE_TABLE(auxiliary, drm_aux_bridge_table);
++
++static struct auxiliary_driver drm_aux_bridge_drv = {
++      .name = "aux_bridge",
++      .id_table = drm_aux_bridge_table,
++      .probe = drm_aux_bridge_probe,
++};
++module_auxiliary_driver(drm_aux_bridge_drv);
++
++MODULE_AUTHOR("Dmitry Baryshkov <dmitry.baryshkov@linaro.org>");
++MODULE_DESCRIPTION("DRM transparent bridge");
++MODULE_LICENSE("GPL");
+diff --git a/include/drm/bridge/aux-bridge.h b/include/drm/bridge/aux-bridge.h
+new file mode 100644
+index 0000000000000..b3a9cc9c862fd
+--- /dev/null
++++ b/include/drm/bridge/aux-bridge.h
+@@ -0,0 +1,19 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2023 Linaro Ltd.
++ *
++ * Author: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
++ */
++#ifndef DRM_AUX_BRIDGE_H
++#define DRM_AUX_BRIDGE_H
++
++#if IS_ENABLED(CONFIG_DRM_AUX_BRIDGE)
++int drm_aux_bridge_register(struct device *parent);
++#else
++static inline int drm_aux_bridge_register(struct device *parent)
++{
++      return 0;
++}
++#endif
++
++#endif
+-- 
+2.43.0
+
diff --git a/queue-6.7/drm-bridge-aux-hpd-separate-allocation-and-registrat.patch b/queue-6.7/drm-bridge-aux-hpd-separate-allocation-and-registrat.patch
new file mode 100644 (file)
index 0000000..df23d7d
--- /dev/null
@@ -0,0 +1,175 @@
+From 357c636cf7159761a5bf455bd7e68e1c884eaa60 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 17 Feb 2024 16:02:24 +0100
+Subject: drm/bridge: aux-hpd: separate allocation and registration
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+[ Upstream commit e5ca263508f7e9d2cf711edf3258d11ca087885c ]
+
+Combining allocation and registration is an anti-pattern that should be
+avoided. Add two new functions for allocating and registering an dp-hpd
+bridge with a proper 'devm' prefix so that it is clear that these are
+device managed interfaces.
+
+       devm_drm_dp_hpd_bridge_alloc()
+       devm_drm_dp_hpd_bridge_add()
+
+The new interface will be used to fix a use-after-free bug in the
+Qualcomm PMIC GLINK driver and may prevent similar issues from being
+introduced elsewhere.
+
+The existing drm_dp_hpd_bridge_register() is reimplemented using the
+above and left in place for now.
+
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Reviewed-by: Bjorn Andersson <andersson@kernel.org>
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Link: https://patchwork.freedesktop.org/patch/msgid/20240217150228.5788-3-johan+linaro@kernel.org
+Stable-dep-of: b979f2d50a09 ("soc: qcom: pmic_glink_altmode: fix drm bridge use-after-free")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/bridge/aux-hpd-bridge.c | 67 +++++++++++++++++++------
+ include/drm/bridge/aux-bridge.h         | 15 ++++++
+ 2 files changed, 67 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/gpu/drm/bridge/aux-hpd-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-bridge.c
+index 5d2ab3a715f9c..44bb771211b82 100644
+--- a/drivers/gpu/drm/bridge/aux-hpd-bridge.c
++++ b/drivers/gpu/drm/bridge/aux-hpd-bridge.c
+@@ -29,16 +29,13 @@ static void drm_aux_hpd_bridge_release(struct device *dev)
+       kfree(adev);
+ }
+-static void drm_aux_hpd_bridge_unregister_adev(void *_adev)
++static void drm_aux_hpd_bridge_free_adev(void *_adev)
+ {
+-      struct auxiliary_device *adev = _adev;
+-
+-      auxiliary_device_delete(adev);
+-      auxiliary_device_uninit(adev);
++      auxiliary_device_uninit(_adev);
+ }
+ /**
+- * drm_dp_hpd_bridge_register - Create a simple HPD DisplayPort bridge
++ * devm_drm_dp_hpd_bridge_alloc - allocate a HPD DisplayPort bridge
+  * @parent: device instance providing this bridge
+  * @np: device node pointer corresponding to this bridge instance
+  *
+@@ -46,11 +43,9 @@ static void drm_aux_hpd_bridge_unregister_adev(void *_adev)
+  * DRM_MODE_CONNECTOR_DisplayPort, which terminates the bridge chain and is
+  * able to send the HPD events.
+  *
+- * Return: device instance that will handle created bridge or an error code
+- * encoded into the pointer.
++ * Return: bridge auxiliary device pointer or an error pointer
+  */
+-struct device *drm_dp_hpd_bridge_register(struct device *parent,
+-                                        struct device_node *np)
++struct auxiliary_device *devm_drm_dp_hpd_bridge_alloc(struct device *parent, struct device_node *np)
+ {
+       struct auxiliary_device *adev;
+       int ret;
+@@ -79,13 +74,55 @@ struct device *drm_dp_hpd_bridge_register(struct device *parent,
+               return ERR_PTR(ret);
+       }
+-      ret = auxiliary_device_add(adev);
+-      if (ret) {
+-              auxiliary_device_uninit(adev);
++      ret = devm_add_action_or_reset(parent, drm_aux_hpd_bridge_free_adev, adev);
++      if (ret)
+               return ERR_PTR(ret);
+-      }
+-      ret = devm_add_action_or_reset(parent, drm_aux_hpd_bridge_unregister_adev, adev);
++      return adev;
++}
++EXPORT_SYMBOL_GPL(devm_drm_dp_hpd_bridge_alloc);
++
++static void drm_aux_hpd_bridge_del_adev(void *_adev)
++{
++      auxiliary_device_delete(_adev);
++}
++
++/**
++ * devm_drm_dp_hpd_bridge_add - register a HDP DisplayPort bridge
++ * @dev: struct device to tie registration lifetime to
++ * @adev: bridge auxiliary device to be registered
++ *
++ * Returns: zero on success or a negative errno
++ */
++int devm_drm_dp_hpd_bridge_add(struct device *dev, struct auxiliary_device *adev)
++{
++      int ret;
++
++      ret = auxiliary_device_add(adev);
++      if (ret)
++              return ret;
++
++      return devm_add_action_or_reset(dev, drm_aux_hpd_bridge_del_adev, adev);
++}
++EXPORT_SYMBOL_GPL(devm_drm_dp_hpd_bridge_add);
++
++/**
++ * drm_dp_hpd_bridge_register - allocate and register a HDP DisplayPort bridge
++ * @parent: device instance providing this bridge
++ * @np: device node pointer corresponding to this bridge instance
++ *
++ * Return: device instance that will handle created bridge or an error pointer
++ */
++struct device *drm_dp_hpd_bridge_register(struct device *parent, struct device_node *np)
++{
++      struct auxiliary_device *adev;
++      int ret;
++
++      adev = devm_drm_dp_hpd_bridge_alloc(parent, np);
++      if (IS_ERR(adev))
++              return ERR_CAST(adev);
++
++      ret = devm_drm_dp_hpd_bridge_add(parent, adev);
+       if (ret)
+               return ERR_PTR(ret);
+diff --git a/include/drm/bridge/aux-bridge.h b/include/drm/bridge/aux-bridge.h
+index 66249ff0858e7..874f177381e34 100644
+--- a/include/drm/bridge/aux-bridge.h
++++ b/include/drm/bridge/aux-bridge.h
+@@ -9,6 +9,8 @@
+ #include <drm/drm_connector.h>
++struct auxiliary_device;
++
+ #if IS_ENABLED(CONFIG_DRM_AUX_BRIDGE)
+ int drm_aux_bridge_register(struct device *parent);
+ #else
+@@ -19,10 +21,23 @@ static inline int drm_aux_bridge_register(struct device *parent)
+ #endif
+ #if IS_ENABLED(CONFIG_DRM_AUX_HPD_BRIDGE)
++struct auxiliary_device *devm_drm_dp_hpd_bridge_alloc(struct device *parent, struct device_node *np);
++int devm_drm_dp_hpd_bridge_add(struct device *dev, struct auxiliary_device *adev);
+ struct device *drm_dp_hpd_bridge_register(struct device *parent,
+                                         struct device_node *np);
+ void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status status);
+ #else
++static inline struct auxiliary_device *devm_drm_dp_hpd_bridge_alloc(struct device *parent,
++                                                                  struct device_node *np)
++{
++      return NULL;
++}
++
++static inline int devm_drm_dp_hpd_bridge_add(struct auxiliary_device *adev)
++{
++      return 0;
++}
++
+ static inline struct device *drm_dp_hpd_bridge_register(struct device *parent,
+                                                       struct device_node *np)
+ {
+-- 
+2.43.0
+
diff --git a/queue-6.7/drm-bridge-implement-generic-dp-hpd-bridge.patch b/queue-6.7/drm-bridge-implement-generic-dp-hpd-bridge.patch
new file mode 100644 (file)
index 0000000..a50a252
--- /dev/null
@@ -0,0 +1,262 @@
+From 4230cbaf334c8b0e1edc5130623d2cd45ec4345d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 3 Dec 2023 14:43:31 +0300
+Subject: drm/bridge: implement generic DP HPD bridge
+
+From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+
+[ Upstream commit e560518a6c2e60f1566473c146fddcff3281f617 ]
+
+Several USB-C controllers implement a pretty simple DRM bridge which
+implements just the HPD notification operations. Add special helper
+for creating such simple bridges.
+
+Acked-by: Neil Armstrong <neil.armstrong@linaro.org>
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Link: https://patchwork.freedesktop.org/patch/msgid/20231203114333.1305826-5-dmitry.baryshkov@linaro.org
+Stable-dep-of: b979f2d50a09 ("soc: qcom: pmic_glink_altmode: fix drm bridge use-after-free")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/bridge/Kconfig          |   8 ++
+ drivers/gpu/drm/bridge/Makefile         |   1 +
+ drivers/gpu/drm/bridge/aux-hpd-bridge.c | 163 ++++++++++++++++++++++++
+ include/drm/bridge/aux-bridge.h         |  18 +++
+ 4 files changed, 190 insertions(+)
+ create mode 100644 drivers/gpu/drm/bridge/aux-hpd-bridge.c
+
+diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
+index a22645efe93a0..efd996f6c1384 100644
+--- a/drivers/gpu/drm/bridge/Kconfig
++++ b/drivers/gpu/drm/bridge/Kconfig
+@@ -21,6 +21,14 @@ config DRM_AUX_BRIDGE
+         Simple transparent bridge that is used by several non-DRM drivers to
+         build bridges chain.
++config DRM_AUX_HPD_BRIDGE
++      tristate
++      depends on DRM_BRIDGE && OF
++      select AUXILIARY_BUS
++      help
++        Simple bridge that terminates the bridge chain and provides HPD
++        support.
++
+ menu "Display Interface Bridges"
+       depends on DRM && DRM_BRIDGE
+diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
+index 918e3bfff079c..017b5832733b2 100644
+--- a/drivers/gpu/drm/bridge/Makefile
++++ b/drivers/gpu/drm/bridge/Makefile
+@@ -1,5 +1,6 @@
+ # SPDX-License-Identifier: GPL-2.0
+ obj-$(CONFIG_DRM_AUX_BRIDGE) += aux-bridge.o
++obj-$(CONFIG_DRM_AUX_HPD_BRIDGE) += aux-hpd-bridge.o
+ obj-$(CONFIG_DRM_CHIPONE_ICN6211) += chipone-icn6211.o
+ obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o
+ obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o
+diff --git a/drivers/gpu/drm/bridge/aux-hpd-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-bridge.c
+new file mode 100644
+index 0000000000000..5d2ab3a715f9c
+--- /dev/null
++++ b/drivers/gpu/drm/bridge/aux-hpd-bridge.c
+@@ -0,0 +1,163 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2023 Linaro Ltd.
++ *
++ * Author: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
++ */
++#include <linux/auxiliary_bus.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
++
++#include <drm/drm_bridge.h>
++#include <drm/bridge/aux-bridge.h>
++
++static DEFINE_IDA(drm_aux_hpd_bridge_ida);
++
++struct drm_aux_hpd_bridge_data {
++      struct drm_bridge bridge;
++      struct device *dev;
++};
++
++static void drm_aux_hpd_bridge_release(struct device *dev)
++{
++      struct auxiliary_device *adev = to_auxiliary_dev(dev);
++
++      ida_free(&drm_aux_hpd_bridge_ida, adev->id);
++
++      of_node_put(adev->dev.platform_data);
++
++      kfree(adev);
++}
++
++static void drm_aux_hpd_bridge_unregister_adev(void *_adev)
++{
++      struct auxiliary_device *adev = _adev;
++
++      auxiliary_device_delete(adev);
++      auxiliary_device_uninit(adev);
++}
++
++/**
++ * drm_dp_hpd_bridge_register - Create a simple HPD DisplayPort bridge
++ * @parent: device instance providing this bridge
++ * @np: device node pointer corresponding to this bridge instance
++ *
++ * Creates a simple DRM bridge with the type set to
++ * DRM_MODE_CONNECTOR_DisplayPort, which terminates the bridge chain and is
++ * able to send the HPD events.
++ *
++ * Return: device instance that will handle created bridge or an error code
++ * encoded into the pointer.
++ */
++struct device *drm_dp_hpd_bridge_register(struct device *parent,
++                                        struct device_node *np)
++{
++      struct auxiliary_device *adev;
++      int ret;
++
++      adev = kzalloc(sizeof(*adev), GFP_KERNEL);
++      if (!adev)
++              return ERR_PTR(-ENOMEM);
++
++      ret = ida_alloc(&drm_aux_hpd_bridge_ida, GFP_KERNEL);
++      if (ret < 0) {
++              kfree(adev);
++              return ERR_PTR(ret);
++      }
++
++      adev->id = ret;
++      adev->name = "dp_hpd_bridge";
++      adev->dev.parent = parent;
++      adev->dev.of_node = parent->of_node;
++      adev->dev.release = drm_aux_hpd_bridge_release;
++      adev->dev.platform_data = np;
++
++      ret = auxiliary_device_init(adev);
++      if (ret) {
++              ida_free(&drm_aux_hpd_bridge_ida, adev->id);
++              kfree(adev);
++              return ERR_PTR(ret);
++      }
++
++      ret = auxiliary_device_add(adev);
++      if (ret) {
++              auxiliary_device_uninit(adev);
++              return ERR_PTR(ret);
++      }
++
++      ret = devm_add_action_or_reset(parent, drm_aux_hpd_bridge_unregister_adev, adev);
++      if (ret)
++              return ERR_PTR(ret);
++
++      return &adev->dev;
++}
++EXPORT_SYMBOL_GPL(drm_dp_hpd_bridge_register);
++
++/**
++ * drm_aux_hpd_bridge_notify - notify hot plug detection events
++ * @dev: device created for the HPD bridge
++ * @status: output connection status
++ *
++ * A wrapper around drm_bridge_hpd_notify() that is used to report hot plug
++ * detection events for bridges created via drm_dp_hpd_bridge_register().
++ *
++ * This function shall be called in a context that can sleep.
++ */
++void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status status)
++{
++      struct auxiliary_device *adev = to_auxiliary_dev(dev);
++      struct drm_aux_hpd_bridge_data *data = auxiliary_get_drvdata(adev);
++
++      if (!data)
++              return;
++
++      drm_bridge_hpd_notify(&data->bridge, status);
++}
++EXPORT_SYMBOL_GPL(drm_aux_hpd_bridge_notify);
++
++static int drm_aux_hpd_bridge_attach(struct drm_bridge *bridge,
++                                   enum drm_bridge_attach_flags flags)
++{
++      return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL;
++}
++
++static const struct drm_bridge_funcs drm_aux_hpd_bridge_funcs = {
++      .attach = drm_aux_hpd_bridge_attach,
++};
++
++static int drm_aux_hpd_bridge_probe(struct auxiliary_device *auxdev,
++                                  const struct auxiliary_device_id *id)
++{
++      struct drm_aux_hpd_bridge_data *data;
++
++      data = devm_kzalloc(&auxdev->dev, sizeof(*data), GFP_KERNEL);
++      if (!data)
++              return -ENOMEM;
++
++      data->dev = &auxdev->dev;
++      data->bridge.funcs = &drm_aux_hpd_bridge_funcs;
++      data->bridge.of_node = dev_get_platdata(data->dev);
++      data->bridge.ops = DRM_BRIDGE_OP_HPD;
++      data->bridge.type = id->driver_data;
++
++      auxiliary_set_drvdata(auxdev, data);
++
++      return devm_drm_bridge_add(data->dev, &data->bridge);
++}
++
++static const struct auxiliary_device_id drm_aux_hpd_bridge_table[] = {
++      { .name = KBUILD_MODNAME ".dp_hpd_bridge", .driver_data = DRM_MODE_CONNECTOR_DisplayPort, },
++      {},
++};
++MODULE_DEVICE_TABLE(auxiliary, drm_aux_hpd_bridge_table);
++
++static struct auxiliary_driver drm_aux_hpd_bridge_drv = {
++      .name = "aux_hpd_bridge",
++      .id_table = drm_aux_hpd_bridge_table,
++      .probe = drm_aux_hpd_bridge_probe,
++};
++module_auxiliary_driver(drm_aux_hpd_bridge_drv);
++
++MODULE_AUTHOR("Dmitry Baryshkov <dmitry.baryshkov@linaro.org>");
++MODULE_DESCRIPTION("DRM HPD bridge");
++MODULE_LICENSE("GPL");
+diff --git a/include/drm/bridge/aux-bridge.h b/include/drm/bridge/aux-bridge.h
+index b3a9cc9c862fd..66249ff0858e7 100644
+--- a/include/drm/bridge/aux-bridge.h
++++ b/include/drm/bridge/aux-bridge.h
+@@ -7,6 +7,8 @@
+ #ifndef DRM_AUX_BRIDGE_H
+ #define DRM_AUX_BRIDGE_H
++#include <drm/drm_connector.h>
++
+ #if IS_ENABLED(CONFIG_DRM_AUX_BRIDGE)
+ int drm_aux_bridge_register(struct device *parent);
+ #else
+@@ -16,4 +18,20 @@ static inline int drm_aux_bridge_register(struct device *parent)
+ }
+ #endif
++#if IS_ENABLED(CONFIG_DRM_AUX_HPD_BRIDGE)
++struct device *drm_dp_hpd_bridge_register(struct device *parent,
++                                        struct device_node *np);
++void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status status);
++#else
++static inline struct device *drm_dp_hpd_bridge_register(struct device *parent,
++                                                      struct device_node *np)
++{
++      return 0;
++}
++
++static inline void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status status)
++{
++}
++#endif
++
+ #endif
+-- 
+2.43.0
+
diff --git a/queue-6.7/dt-bindings-dma-fsl-edma-add-fsl-edma.h-to-prevent-h.patch b/queue-6.7/dt-bindings-dma-fsl-edma-add-fsl-edma.h-to-prevent-h.patch
new file mode 100644 (file)
index 0000000..e3dd808
--- /dev/null
@@ -0,0 +1,57 @@
+From 82feb6d3481ed699bc0a8b95fb9846a5d5dd2bd0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Nov 2023 10:48:22 -0500
+Subject: dt-bindings: dma: fsl-edma: Add fsl-edma.h to prevent hardcoding in
+ dts
+
+From: Frank Li <Frank.Li@nxp.com>
+
+[ Upstream commit 1e9b05258271b76ccc04a4b535009d2cb596506a ]
+
+Introduce a common dt-bindings header file, fsl-edma.h, shared between
+the driver and dts files. This addition aims to eliminate hardcoded values
+in dts files, promoting maintainability and consistency.
+
+DTS header file not support BIT() macro yet. Directly use 2^n number.
+
+Signed-off-by: Frank Li <Frank.Li@nxp.com>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Link: https://lore.kernel.org/r/20231114154824.3617255-3-Frank.Li@nxp.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Stable-dep-of: a79f949a5ce1 ("dmaengine: fsl-edma: correct max_segment_size setting")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/dt-bindings/dma/fsl-edma.h | 21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+ create mode 100644 include/dt-bindings/dma/fsl-edma.h
+
+diff --git a/include/dt-bindings/dma/fsl-edma.h b/include/dt-bindings/dma/fsl-edma.h
+new file mode 100644
+index 0000000000000..fd11478cfe9cc
+--- /dev/null
++++ b/include/dt-bindings/dma/fsl-edma.h
+@@ -0,0 +1,21 @@
++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
++
++#ifndef _FSL_EDMA_DT_BINDING_H_
++#define _FSL_EDMA_DT_BINDING_H_
++
++/* Receive Channel */
++#define FSL_EDMA_RX           0x1
++
++/* iMX8 audio remote DMA */
++#define FSL_EDMA_REMOTE               0x2
++
++/* FIFO is continue memory region */
++#define FSL_EDMA_MULTI_FIFO   0x4
++
++/* Channel need stick to even channel */
++#define FSL_EDMA_EVEN_CH      0x8
++
++/* Channel need stick to odd channel */
++#define FSL_EDMA_ODD_CH               0x10
++
++#endif
+-- 
+2.43.0
+
diff --git a/queue-6.7/series b/queue-6.7/series
new file mode 100644 (file)
index 0000000..6b07d27
--- /dev/null
@@ -0,0 +1,8 @@
+drm-bridge-add-transparent-bridge-helper.patch
+drm-bridge-implement-generic-dp-hpd-bridge.patch
+soc-qcom-pmic-glink-switch-to-drm_aux_hpd_bridge.patch
+drm-bridge-aux-hpd-separate-allocation-and-registrat.patch
+soc-qcom-pmic_glink_altmode-fix-drm-bridge-use-after.patch
+dt-bindings-dma-fsl-edma-add-fsl-edma.h-to-prevent-h.patch
+dmaengine-fsl-edma-utilize-common-dt-binding-header-.patch
+dmaengine-fsl-edma-correct-max_segment_size-setting.patch
diff --git a/queue-6.7/soc-qcom-pmic-glink-switch-to-drm_aux_hpd_bridge.patch b/queue-6.7/soc-qcom-pmic-glink-switch-to-drm_aux_hpd_bridge.patch
new file mode 100644 (file)
index 0000000..bba56aa
--- /dev/null
@@ -0,0 +1,111 @@
+From c2f051c3e81e9216cc2ca7096b1dfd0093ae89a3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 3 Dec 2023 14:43:32 +0300
+Subject: soc: qcom: pmic-glink: switch to DRM_AUX_HPD_BRIDGE
+
+From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+
+[ Upstream commit 2bcca96abfbf89d26fc10fc92e40532bb2ae8891 ]
+
+Use the freshly defined DRM_AUX_HPD_BRIDGE instead of open-coding the
+same functionality for the DRM bridge chain termination.
+
+Reviewed-by: Bjorn Andersson <andersson@kernel.org>
+Acked-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Link: https://patchwork.freedesktop.org/patch/msgid/20231203114333.1305826-6-dmitry.baryshkov@linaro.org
+Stable-dep-of: b979f2d50a09 ("soc: qcom: pmic_glink_altmode: fix drm bridge use-after-free")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/qcom/Kconfig              |  1 +
+ drivers/soc/qcom/pmic_glink_altmode.c | 33 ++++++++-------------------
+ 2 files changed, 10 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
+index b3634e10f6f5e..c954001ae79ec 100644
+--- a/drivers/soc/qcom/Kconfig
++++ b/drivers/soc/qcom/Kconfig
+@@ -86,6 +86,7 @@ config QCOM_PMIC_GLINK
+       depends on OF
+       select AUXILIARY_BUS
+       select QCOM_PDR_HELPERS
++      select DRM_AUX_HPD_BRIDGE
+       help
+         The Qualcomm PMIC GLINK driver provides access, over GLINK, to the
+         USB and battery firmware running on one of the coprocessors in
+diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c
+index 7ee52cf2570fa..1539ccb7a346d 100644
+--- a/drivers/soc/qcom/pmic_glink_altmode.c
++++ b/drivers/soc/qcom/pmic_glink_altmode.c
+@@ -11,7 +11,7 @@
+ #include <linux/mutex.h>
+ #include <linux/property.h>
+ #include <linux/soc/qcom/pdr.h>
+-#include <drm/drm_bridge.h>
++#include <drm/bridge/aux-bridge.h>
+ #include <linux/usb/typec_altmode.h>
+ #include <linux/usb/typec_dp.h>
+@@ -76,7 +76,7 @@ struct pmic_glink_altmode_port {
+       struct work_struct work;
+-      struct drm_bridge bridge;
++      struct device *bridge;
+       enum typec_orientation orientation;
+       u16 svid;
+@@ -230,10 +230,10 @@ static void pmic_glink_altmode_worker(struct work_struct *work)
+       else
+               pmic_glink_altmode_enable_usb(altmode, alt_port);
+-      if (alt_port->hpd_state)
+-              drm_bridge_hpd_notify(&alt_port->bridge, connector_status_connected);
+-      else
+-              drm_bridge_hpd_notify(&alt_port->bridge, connector_status_disconnected);
++      drm_aux_hpd_bridge_notify(alt_port->bridge,
++                                alt_port->hpd_state ?
++                                connector_status_connected :
++                                connector_status_disconnected);
+       pmic_glink_altmode_request(altmode, ALTMODE_PAN_ACK, alt_port->index);
+ };
+@@ -365,16 +365,6 @@ static void pmic_glink_altmode_callback(const void *data, size_t len, void *priv
+       }
+ }
+-static int pmic_glink_altmode_attach(struct drm_bridge *bridge,
+-                                   enum drm_bridge_attach_flags flags)
+-{
+-      return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL;
+-}
+-
+-static const struct drm_bridge_funcs pmic_glink_altmode_bridge_funcs = {
+-      .attach = pmic_glink_altmode_attach,
+-};
+-
+ static void pmic_glink_altmode_put_retimer(void *data)
+ {
+       typec_retimer_put(data);
+@@ -464,15 +454,10 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev,
+               alt_port->index = port;
+               INIT_WORK(&alt_port->work, pmic_glink_altmode_worker);
+-              alt_port->bridge.funcs = &pmic_glink_altmode_bridge_funcs;
+-              alt_port->bridge.of_node = to_of_node(fwnode);
+-              alt_port->bridge.ops = DRM_BRIDGE_OP_HPD;
+-              alt_port->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
+-
+-              ret = devm_drm_bridge_add(dev, &alt_port->bridge);
+-              if (ret) {
++              alt_port->bridge = drm_dp_hpd_bridge_register(dev, to_of_node(fwnode));
++              if (IS_ERR(alt_port->bridge)) {
+                       fwnode_handle_put(fwnode);
+-                      return ret;
++                      return PTR_ERR(alt_port->bridge);
+               }
+               alt_port->dp_alt.svid = USB_TYPEC_DP_SID;
+-- 
+2.43.0
+
diff --git a/queue-6.7/soc-qcom-pmic_glink_altmode-fix-drm-bridge-use-after.patch b/queue-6.7/soc-qcom-pmic_glink_altmode-fix-drm-bridge-use-after.patch
new file mode 100644 (file)
index 0000000..bbb518d
--- /dev/null
@@ -0,0 +1,123 @@
+From 34ffd4992df436d6a57996dbb04e9105b44c6a9f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 17 Feb 2024 16:02:25 +0100
+Subject: soc: qcom: pmic_glink_altmode: fix drm bridge use-after-free
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+[ Upstream commit b979f2d50a099f3402418d7ff5f26c3952fb08bb ]
+
+A recent DRM series purporting to simplify support for "transparent
+bridges" and handling of probe deferrals ironically exposed a
+use-after-free issue on pmic_glink_altmode probe deferral.
+
+This has manifested itself as the display subsystem occasionally failing
+to initialise and NULL-pointer dereferences during boot of machines like
+the Lenovo ThinkPad X13s.
+
+Specifically, the dp-hpd bridge is currently registered before all
+resources have been acquired which means that it can also be
+deregistered on probe deferrals.
+
+In the meantime there is a race window where the new aux bridge driver
+(or PHY driver previously) may have looked up the dp-hpd bridge and
+stored a (non-reference-counted) pointer to the bridge which is about to
+be deallocated.
+
+When the display controller is later initialised, this triggers a
+use-after-free when attaching the bridges:
+
+       dp -> aux -> dp-hpd (freed)
+
+which may, for example, result in the freed bridge failing to attach:
+
+       [drm:drm_bridge_attach [drm]] *ERROR* failed to attach bridge /soc@0/phy@88eb000 to encoder TMDS-31: -16
+
+or a NULL-pointer dereference:
+
+       Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000
+       ...
+       Call trace:
+         drm_bridge_attach+0x70/0x1a8 [drm]
+         drm_aux_bridge_attach+0x24/0x38 [aux_bridge]
+         drm_bridge_attach+0x80/0x1a8 [drm]
+         dp_bridge_init+0xa8/0x15c [msm]
+         msm_dp_modeset_init+0x28/0xc4 [msm]
+
+The DRM bridge implementation is clearly fragile and implicitly built on
+the assumption that bridges may never go away. In this case, the fix is
+to move the bridge registration in the pmic_glink_altmode driver to
+after all resources have been looked up.
+
+Incidentally, with the new dp-hpd bridge implementation, which registers
+child devices, this is also a requirement due to a long-standing issue
+in driver core that can otherwise lead to a probe deferral loop (see
+commit fbc35b45f9f6 ("Add documentation on meaning of -EPROBE_DEFER")).
+
+[DB: slightly fixed commit message by adding the word 'commit']
+Fixes: 080b4e24852b ("soc: qcom: pmic_glink: Introduce altmode support")
+Fixes: 2bcca96abfbf ("soc: qcom: pmic-glink: switch to DRM_AUX_HPD_BRIDGE")
+Cc: <stable@vger.kernel.org>      # 6.3
+Cc: Bjorn Andersson <andersson@kernel.org>
+Cc: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Reviewed-by: Bjorn Andersson <andersson@kernel.org>
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Link: https://patchwork.freedesktop.org/patch/msgid/20240217150228.5788-4-johan+linaro@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/qcom/pmic_glink_altmode.c | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c
+index 1539ccb7a346d..e1d32e1b79902 100644
+--- a/drivers/soc/qcom/pmic_glink_altmode.c
++++ b/drivers/soc/qcom/pmic_glink_altmode.c
+@@ -76,7 +76,7 @@ struct pmic_glink_altmode_port {
+       struct work_struct work;
+-      struct device *bridge;
++      struct auxiliary_device *bridge;
+       enum typec_orientation orientation;
+       u16 svid;
+@@ -230,7 +230,7 @@ static void pmic_glink_altmode_worker(struct work_struct *work)
+       else
+               pmic_glink_altmode_enable_usb(altmode, alt_port);
+-      drm_aux_hpd_bridge_notify(alt_port->bridge,
++      drm_aux_hpd_bridge_notify(&alt_port->bridge->dev,
+                                 alt_port->hpd_state ?
+                                 connector_status_connected :
+                                 connector_status_disconnected);
+@@ -454,7 +454,7 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev,
+               alt_port->index = port;
+               INIT_WORK(&alt_port->work, pmic_glink_altmode_worker);
+-              alt_port->bridge = drm_dp_hpd_bridge_register(dev, to_of_node(fwnode));
++              alt_port->bridge = devm_drm_dp_hpd_bridge_alloc(dev, to_of_node(fwnode));
+               if (IS_ERR(alt_port->bridge)) {
+                       fwnode_handle_put(fwnode);
+                       return PTR_ERR(alt_port->bridge);
+@@ -510,6 +510,16 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev,
+               }
+       }
++      for (port = 0; port < ARRAY_SIZE(altmode->ports); port++) {
++              alt_port = &altmode->ports[port];
++              if (!alt_port->bridge)
++                      continue;
++
++              ret = devm_drm_dp_hpd_bridge_add(dev, alt_port->bridge);
++              if (ret)
++                      return ret;
++      }
++
+       altmode->client = devm_pmic_glink_register_client(dev,
+                                                         altmode->owner_id,
+                                                         pmic_glink_altmode_callback,
+-- 
+2.43.0
+