drm/msm/dsi: free TX buffer in unbind
authorDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Thu, 12 Oct 2023 01:29:09 +0000 (04:29 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 20 Nov 2023 10:59:12 +0000 (11:59 +0100)
[ Upstream commit 5e05be78264594634860087953649487f486ffcc ]

If the drm/msm init code gets an error during output modeset
initialisation, the kernel will report an error regarding DRM memory
manager not being clean during shutdown. This is because
msm_dsi_modeset_init() allocates a piece of GEM memory for the TX
buffer, but destruction of the buffer happens only at
msm_dsi_host_destroy(), which is called during DSI driver's remove()
time, much later than the DRM MM shutdown.

To solve this issue, move the TX buffer destruction to dsi_unbind(), so
that the buffer is destructed at the correct time. Note, we also have to
store a reference to the address space, because priv->kms->aspace is
cleared before components are unbound.

Reported-by: Bjorn Andersson <andersson@kernel.org>
Fixes: 8f59ee9a570c ("drm/msm/dsi: Adjust probe order")
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Patchwork: https://patchwork.freedesktop.org/patch/562238/
Signed-off-by: Rob Clark <robdclark@chromium.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/gpu/drm/msm/dsi/dsi.c
drivers/gpu/drm/msm/dsi/dsi.h
drivers/gpu/drm/msm/dsi/dsi_host.c

index baab79a..32f965b 100644 (file)
@@ -126,6 +126,7 @@ static void dsi_unbind(struct device *dev, struct device *master,
        struct msm_drm_private *priv = dev_get_drvdata(master);
        struct msm_dsi *msm_dsi = dev_get_drvdata(dev);
 
+       msm_dsi_tx_buf_free(msm_dsi->host);
        priv->dsi[msm_dsi->id] = NULL;
 }
 
index bd3763a..3b46617 100644 (file)
@@ -125,6 +125,7 @@ int dsi_tx_buf_alloc_v2(struct msm_dsi_host *msm_host, int size);
 void *dsi_tx_buf_get_6g(struct msm_dsi_host *msm_host);
 void *dsi_tx_buf_get_v2(struct msm_dsi_host *msm_host);
 void dsi_tx_buf_put_6g(struct msm_dsi_host *msm_host);
+void msm_dsi_tx_buf_free(struct mipi_dsi_host *mipi_host);
 int dsi_dma_base_get_6g(struct msm_dsi_host *msm_host, uint64_t *iova);
 int dsi_dma_base_get_v2(struct msm_dsi_host *msm_host, uint64_t *iova);
 int dsi_clk_init_v2(struct msm_dsi_host *msm_host);
index 2395d5a..4708668 100644 (file)
@@ -147,6 +147,7 @@ struct msm_dsi_host {
 
        /* DSI 6G TX buffer*/
        struct drm_gem_object *tx_gem_obj;
+       struct msm_gem_address_space *aspace;
 
        /* DSI v2 TX buffer */
        void *tx_buf;
@@ -1111,8 +1112,10 @@ int dsi_tx_buf_alloc_6g(struct msm_dsi_host *msm_host, int size)
        uint64_t iova;
        u8 *data;
 
+       msm_host->aspace = msm_gem_address_space_get(priv->kms->aspace);
+
        data = msm_gem_kernel_new(dev, size, MSM_BO_WC,
-                                       priv->kms->aspace,
+                                       msm_host->aspace,
                                        &msm_host->tx_gem_obj, &iova);
 
        if (IS_ERR(data)) {
@@ -1141,10 +1144,10 @@ int dsi_tx_buf_alloc_v2(struct msm_dsi_host *msm_host, int size)
        return 0;
 }
 
-static void dsi_tx_buf_free(struct msm_dsi_host *msm_host)
+void msm_dsi_tx_buf_free(struct mipi_dsi_host *host)
 {
+       struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
        struct drm_device *dev = msm_host->dev;
-       struct msm_drm_private *priv;
 
        /*
         * This is possible if we're tearing down before we've had a chance to
@@ -1155,10 +1158,11 @@ static void dsi_tx_buf_free(struct msm_dsi_host *msm_host)
        if (!dev)
                return;
 
-       priv = dev->dev_private;
        if (msm_host->tx_gem_obj) {
-               msm_gem_kernel_put(msm_host->tx_gem_obj, priv->kms->aspace);
+               msm_gem_kernel_put(msm_host->tx_gem_obj, msm_host->aspace);
+               msm_gem_address_space_put(msm_host->aspace);
                msm_host->tx_gem_obj = NULL;
+               msm_host->aspace = NULL;
        }
 
        if (msm_host->tx_buf)
@@ -1944,7 +1948,6 @@ void msm_dsi_host_destroy(struct mipi_dsi_host *host)
        struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
 
        DBG("");
-       dsi_tx_buf_free(msm_host);
        if (msm_host->workqueue) {
                destroy_workqueue(msm_host->workqueue);
                msm_host->workqueue = NULL;