Commit 5e05be78 authored by Dmitry Baryshkov's avatar Dmitry Baryshkov Committed by Rob Clark
Browse files

drm/msm/dsi: free TX buffer in unbind



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: default avatarBjorn Andersson <andersson@kernel.org>
Fixes: 8f59ee9a ("drm/msm/dsi: Adjust probe order")
Signed-off-by: default avatarDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Patchwork: https://patchwork.freedesktop.org/patch/562238/


Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
parent 69b321b2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -131,6 +131,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;
}

+1 −0
Original line number Diff line number Diff line
@@ -124,6 +124,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);
+9 −6
Original line number Diff line number Diff line
@@ -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;
@@ -1134,8 +1135,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)) {
@@ -1164,10 +1167,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
@@ -1178,10 +1181,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)
@@ -1967,7 +1971,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;