On Mon, Apr 20, 2026 at 05:06:57PM +0200, Osama Abdelkader wrote:
> Tear down and clear the global DSI host/device/bridge singleton state
> when unregistering the host so probe retries and remove/reprobe cycles
> start from a clean state.
> 
> Guard the clock-disable path in kmb_dsi_host_unregister() to avoid
> dereferencing error pointers from early probe failure paths.
> Signed-off-by: Osama Abdelkader <[email protected]>
> ---
>  drivers/gpu/drm/kmb/kmb_dsi.c | 44 ++++++++++++++++++++++++++++++-----
>  1 file changed, 38 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/kmb/kmb_dsi.c b/drivers/gpu/drm/kmb/kmb_dsi.c
> index aeb2f9f98f23..500dc00ba6ae 100644
> --- a/drivers/gpu/drm/kmb/kmb_dsi.c
> +++ b/drivers/gpu/drm/kmb/kmb_dsi.c
> @@ -5,6 +5,7 @@
>  
>  #include <linux/clk.h>
>  #include <linux/delay.h>
> +#include <linux/err.h>
>  #include <linux/of.h>
>  #include <linux/of_graph.h>
>  #include <linux/mfd/syscon.h>
> @@ -182,8 +183,18 @@ static void kmb_dsi_clk_disable(struct kmb_dsi *kmb_dsi)
>  
>  void kmb_dsi_host_unregister(struct kmb_dsi *kmb_dsi)
>  {
> -     kmb_dsi_clk_disable(kmb_dsi);
> -     mipi_dsi_host_unregister(kmb_dsi->host);
> +     if (!IS_ERR_OR_NULL(kmb_dsi))
> +             kmb_dsi_clk_disable(kmb_dsi);
> +
> +     if (dsi_host) {
> +             mipi_dsi_host_unregister(dsi_host);
> +             kfree(dsi_host);
> +             dsi_host = NULL;
> +     }
> +
> +     kfree(dsi_device);
> +     dsi_device = NULL;
> +     adv_bridge = NULL;
>  }
>  
>  /*
> @@ -217,6 +228,8 @@ static const struct mipi_dsi_host_ops kmb_dsi_host_ops = {
>  int kmb_dsi_host_bridge_init(struct device *dev)
>  {
>       struct device_node *encoder_node, *dsi_out;
> +     bool host_registered = false;
> +     int ret;
>  
>       /* Create and register MIPI DSI host */
>       if (!dsi_host) {
> @@ -230,25 +243,38 @@ int kmb_dsi_host_bridge_init(struct device *dev)
>                       dsi_device = kzalloc_obj(*dsi_device);
>                       if (!dsi_device) {
>                               kfree(dsi_host);
> +                             dsi_host = NULL;
>                               return -ENOMEM;
>                       }
>               }
>  
>               dsi_host->dev = dev;
> -             mipi_dsi_host_register(dsi_host);
> +             ret = mipi_dsi_host_register(dsi_host);
> +             if (ret) {
> +                     DRM_ERROR("failed to register dsi host\n");
> +                     kfree(dsi_device);
> +                     dsi_device = NULL;
> +                     kfree(dsi_host);
> +                     dsi_host = NULL;
> +                     return ret;
> +             }
> +
> +             host_registered = true;
>       }
>  
>       /* Find ADV7535 node and initialize it */
>       dsi_out = of_graph_get_endpoint_by_regs(dev->of_node, 0, 1);
>       if (!dsi_out) {
>               DRM_ERROR("Failed to get dsi_out node info from DT\n");
> -             return -EINVAL;
> +             ret = -EINVAL;
> +             goto err_unregister_host;
>       }
>       encoder_node = of_graph_get_remote_port_parent(dsi_out);
>       if (!encoder_node) {
>               of_node_put(dsi_out);
>               DRM_ERROR("Failed to get bridge info from DT\n");
> -             return -EINVAL;
> +             ret = -EINVAL;
> +             goto err_unregister_host;
>       }
>       /* Locate drm bridge from the hdmi encoder DT node */
>       adv_bridge = of_drm_find_bridge(encoder_node);
> @@ -256,10 +282,16 @@ int kmb_dsi_host_bridge_init(struct device *dev)
>       of_node_put(encoder_node);
>       if (!adv_bridge) {
>               DRM_DEBUG("Wait for external bridge driver DT\n");
> -             return -EPROBE_DEFER;
> +             ret = -EPROBE_DEFER;
> +             goto err_unregister_host;
>       }
>  
>       return 0;
> +
> +err_unregister_host:
> +     if (host_registered)
> +             kmb_dsi_host_unregister(NULL);
> +     return ret;
>  }
>  
>  static u32 mipi_get_datatype_params(u32 data_type, u32 data_mode,
> -- 
> 2.43.0
> 
ping.

Reply via email to