Commit e3c3b6e6 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'exynos-drm-fixes-for-v5.6-rc5-v2' of...

Merge tag 'exynos-drm-fixes-for-v5.6-rc5-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos

 into drm-fixes

Fix IOMMU initialization failure when Exynos DRM driver is rebound,
and also fix memory leak to iommu mapping object, which was
detected by kmemleak detector.

Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Inki Dae <inki.dae@samsung.com>
Link: https://patchwork.freedesktop.org/patch/msgid/1583887109-4148-1-git-send-email-inki.dae@samsung.com
parents 2c523b34 07dc3678
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ static const char * const decon_clks_name[] = {
struct decon_context {
	struct device			*dev;
	struct drm_device		*drm_dev;
	void				*dma_priv;
	struct exynos_drm_crtc		*crtc;
	struct exynos_drm_plane		planes[WINDOWS_NR];
	struct exynos_drm_plane_config	configs[WINDOWS_NR];
@@ -644,7 +645,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data)

	decon_clear_channels(ctx->crtc);

	return exynos_drm_register_dma(drm_dev, dev);
	return exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);
}

static void decon_unbind(struct device *dev, struct device *master, void *data)
@@ -654,7 +655,7 @@ static void decon_unbind(struct device *dev, struct device *master, void *data)
	decon_atomic_disable(ctx->crtc);

	/* detach this sub driver from iommu mapping if supported. */
	exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev);
	exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev, &ctx->dma_priv);
}

static const struct component_ops decon_component_ops = {
+3 −2
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@
struct decon_context {
	struct device			*dev;
	struct drm_device		*drm_dev;
	void				*dma_priv;
	struct exynos_drm_crtc		*crtc;
	struct exynos_drm_plane		planes[WINDOWS_NR];
	struct exynos_drm_plane_config	configs[WINDOWS_NR];
@@ -127,13 +128,13 @@ static int decon_ctx_initialize(struct decon_context *ctx,

	decon_clear_channels(ctx->crtc);

	return exynos_drm_register_dma(drm_dev, ctx->dev);
	return exynos_drm_register_dma(drm_dev, ctx->dev, &ctx->dma_priv);
}

static void decon_ctx_remove(struct decon_context *ctx)
{
	/* detach this sub driver from iommu mapping if supported. */
	exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev);
	exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev, &ctx->dma_priv);
}

static u32 decon_calc_clkdiv(struct decon_context *ctx,
+19 −9
Original line number Diff line number Diff line
@@ -58,7 +58,7 @@ static inline void clear_dma_max_seg_size(struct device *dev)
 * mapping.
 */
static int drm_iommu_attach_device(struct drm_device *drm_dev,
				struct device *subdrv_dev)
				struct device *subdrv_dev, void **dma_priv)
{
	struct exynos_drm_private *priv = drm_dev->dev_private;
	int ret;
@@ -74,7 +74,14 @@ static int drm_iommu_attach_device(struct drm_device *drm_dev,
		return ret;

	if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
		if (to_dma_iommu_mapping(subdrv_dev))
		/*
		 * Keep the original DMA mapping of the sub-device and
		 * restore it on Exynos DRM detach, otherwise the DMA
		 * framework considers it as IOMMU-less during the next
		 * probe (in case of deferred probe or modular build)
		 */
		*dma_priv = to_dma_iommu_mapping(subdrv_dev);
		if (*dma_priv)
			arm_iommu_detach_device(subdrv_dev);

		ret = arm_iommu_attach_device(subdrv_dev, priv->mapping);
@@ -98,19 +105,21 @@ static int drm_iommu_attach_device(struct drm_device *drm_dev,
 * mapping
 */
static void drm_iommu_detach_device(struct drm_device *drm_dev,
				struct device *subdrv_dev)
				    struct device *subdrv_dev, void **dma_priv)
{
	struct exynos_drm_private *priv = drm_dev->dev_private;

	if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU))
	if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
		arm_iommu_detach_device(subdrv_dev);
	else if (IS_ENABLED(CONFIG_IOMMU_DMA))
		arm_iommu_attach_device(subdrv_dev, *dma_priv);
	} else if (IS_ENABLED(CONFIG_IOMMU_DMA))
		iommu_detach_device(priv->mapping, subdrv_dev);

	clear_dma_max_seg_size(subdrv_dev);
}

int exynos_drm_register_dma(struct drm_device *drm, struct device *dev)
int exynos_drm_register_dma(struct drm_device *drm, struct device *dev,
			    void **dma_priv)
{
	struct exynos_drm_private *priv = drm->dev_private;

@@ -137,13 +146,14 @@ int exynos_drm_register_dma(struct drm_device *drm, struct device *dev)
		priv->mapping = mapping;
	}

	return drm_iommu_attach_device(drm, dev);
	return drm_iommu_attach_device(drm, dev, dma_priv);
}

void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev)
void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev,
			       void **dma_priv)
{
	if (IS_ENABLED(CONFIG_EXYNOS_IOMMU))
		drm_iommu_detach_device(drm, dev);
		drm_iommu_detach_device(drm, dev, dma_priv);
}

void exynos_drm_cleanup_dma(struct drm_device *drm)
+4 −2
Original line number Diff line number Diff line
@@ -223,8 +223,10 @@ static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
	return priv->mapping ? true : false;
}

int exynos_drm_register_dma(struct drm_device *drm, struct device *dev);
void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev);
int exynos_drm_register_dma(struct drm_device *drm, struct device *dev,
			    void **dma_priv);
void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev,
			       void **dma_priv);
void exynos_drm_cleanup_dma(struct drm_device *drm);

#ifdef CONFIG_DRM_EXYNOS_DPI
+3 −2
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ struct fimc_scaler {
struct fimc_context {
	struct exynos_drm_ipp ipp;
	struct drm_device *drm_dev;
	void		*dma_priv;
	struct device	*dev;
	struct exynos_drm_ipp_task	*task;
	struct exynos_drm_ipp_formats	*formats;
@@ -1133,7 +1134,7 @@ static int fimc_bind(struct device *dev, struct device *master, void *data)

	ctx->drm_dev = drm_dev;
	ipp->drm_dev = drm_dev;
	exynos_drm_register_dma(drm_dev, dev);
	exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);

	exynos_drm_ipp_register(dev, ipp, &ipp_funcs,
			DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
@@ -1153,7 +1154,7 @@ static void fimc_unbind(struct device *dev, struct device *master,
	struct exynos_drm_ipp *ipp = &ctx->ipp;

	exynos_drm_ipp_unregister(dev, ipp);
	exynos_drm_unregister_dma(drm_dev, dev);
	exynos_drm_unregister_dma(drm_dev, dev, &ctx->dma_priv);
}

static const struct component_ops fimc_component_ops = {
Loading